diff --git a/404.html b/404.html index c3673954..7ff6ceb2 100644 --- a/404.html +++ b/404.html @@ -6,13 +6,13 @@ Page Not Found | Dashy - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/18ba09e8.2035098a.js b/assets/js/18ba09e8.2035098a.js new file mode 100644 index 00000000..69d4d07a --- /dev/null +++ b/assets/js/18ba09e8.2035098a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[849],{5680:(t,e,a)=>{a.d(e,{xA:()=>y,yg:()=>b});var n=a(6540);function l(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function g(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function r(t){for(var e=1;e=0||(l[a]=t[a]);return l}(t,e);if(Object.getOwnPropertySymbols){var g=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(l[a]=t[a])}return l}var i=n.createContext({}),s=function(t){var e=n.useContext(i),a=e;return t&&(a="function"==typeof t?t(e):r(r({},e),t)),a},y=function(t){var e=s(t.components);return n.createElement(i.Provider,{value:e},t.children)},h="mdxType",o={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},c=n.forwardRef((function(t,e){var a=t.components,l=t.mdxType,g=t.originalType,i=t.parentName,y=u(t,["components","mdxType","originalType","parentName"]),h=s(a),c=l,b=h["".concat(i,".").concat(c)]||h[c]||o[c]||g;return a?n.createElement(b,r(r({ref:e},y),{},{components:a})):n.createElement(b,r({ref:e},y))}));function b(t,e){var a=arguments,l=e&&e.mdxType;if("string"==typeof t||l){var g=a.length,r=new Array(g);r[0]=c;var u={};for(var i in e)hasOwnProperty.call(e,i)&&(u[i]=e[i]);u.originalType=t,u[h]="string"==typeof t?t:l,r[1]=u;for(var s=2;s{a.r(e),a.d(e,{contentTitle:()=>r,default:()=>h,frontMatter:()=>g,metadata:()=>u,toc:()=>i});var n=a(8168),l=(a(6540),a(5680));const g={},r="Credits",u={unversionedId:"credits",id:"credits",isDocsHomePage:!1,title:"Credits",description:"Sponsors",source:"@site/docs/credits.md",sourceDirName:".",slug:"/credits",permalink:"/docs/credits",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/credits.md",version:"current",frontMatter:{}},i=[{value:"Sponsors",id:"sponsors",children:[]},{value:"Contributors",id:"contributors",children:[]},{value:"Helpful Users",id:"helpful-users",children:[]},{value:"Bots",id:"bots",children:[]},{value:"Newest Stargazers",id:"newest-stargazers",children:[]},{value:"Dependencies",id:"dependencies",children:[{value:"Core",id:"core",children:[]},{value:"Utilities",id:"utilities",children:[]},{value:"Frontend Components",id:"frontend-components",children:[]},{value:"Backup & Sync Server",id:"backup--sync-server",children:[]},{value:"External Services",id:"external-services",children:[]},{value:"Actions",id:"actions",children:[]}]},{value:"You",id:"you",children:[]}],s={toc:i},y="wrapper";function h(t){let{components:e,...a}=t;return(0,l.yg)(y,(0,n.A)({},s,a,{components:e,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"credits"},"Credits"),(0,l.yg)("h2",{id:"sponsors"},"Sponsors"),(0,l.yg)("table",null,(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/koconder"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/25068?u=582657b23622aaa3dfe68bd028a780f272f456fa&v=4",width:"80;",alt:"koconder"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Vincent Koc")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/peng1can"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/225854?v=4",width:"80;",alt:"peng1can"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alydemah"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/652035?u=ac2c04e474da37bfeafcfa25076cc1800997aedb&v=4",width:"80;",alt:"alydemah"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Aly Mohamed")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bgadrian"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/830001?u=69f115baad2fcd8c14eb05bdbf5cd80f4649a95a&v=4",width:"80;",alt:"bgadrian"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"B.G.Adrian")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/tbjers"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1117052?u=539d96d5e581b3139c75713ce35b89a36626404c&v=4",width:"80;",alt:"tbjers"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Torgny Bjers")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/emlazzarin"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1141361?u=714e3487a3f2e0df721b01a0133945f075d3ff68&v=4",width:"80;",alt:"emlazzarin"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Eddy Lazzarin"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/AnandChowdhary"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/2841780?u=747e554b3a7f12eb20b7910e1c87d817844f714f&v=4",width:"80;",alt:"AnandChowdhary"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Anand Chowdhary")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/shrippen"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/2873570?v=4",width:"80;",alt:"shrippen"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bile0026"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5022496?u=aec96ad173c0ea9baaba93807efa8a848af6595c&v=4",width:"80;",alt:"bile0026"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Zach Biles")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/UlisesGascon"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5110813?u=3c41facd8aa26154b9451de237c34b0f78d672a5&v=4",width:"80;",alt:"UlisesGascon"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ulises Gasc\xf3n")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/digitalarche"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6546135?u=d033c9c16e8367987aec3f9ff5922bc67dd1eedf&v=4",width:"80;",alt:"digitalarche"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Digital Archeology")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/InDieTasten"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7047377?u=8d8f8017628b38bc46dcbf3620e194b01d3fb2d1&v=4",width:"80;",alt:"InDieTasten"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bmcgonag"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7346620?u=2a0f9284f3e12ac1cc15288c254d1ec68a5081e8&v=4",width:"80;",alt:"bmcgonag"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Brian McGonagill")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/vlad-timofeev"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11474041?u=eee43705b54d2ec9f51fc4fcce5ad18dd17c87e4&v=4",width:"80;",alt:"vlad-timofeev"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Vlad Timofeev")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/helixzz"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/12218889?u=d06d0c103dfbdb99450623064f7da3c5a3675fb6&v=4",width:"80;",alt:"helixzz"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"HeliXZz")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/mryesiller"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/24632172?v=4",width:"80;",alt:"mryesiller"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"G\xf6ksel Ye\u015filler")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/forwardemail"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/32481436?v=4",width:"80;",alt:"forwardemail"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Forward Email - Open-source & Privacy-focused Email Service (2023)")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Bastii717"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/53431819?u=604977bed6ad6875ada890d0d3765a4cacc2fa14&v=4",width:"80;",alt:"Bastii717"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/frankdez93"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/87549420?v=4",width:"80;",alt:"frankdez93"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/ratty222"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/92832598?u=137b65530cbd5f5af9c24cde51baa6cc77cc934b&v=4",width:"80;",alt:"ratty222"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ratty222")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/hernanpopper"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/104868017?v=4",width:"80;",alt:"hernanpopper"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/NixyJuppie"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/138570196?u=b102c222487905728b858704962d32759df29ebe&v=4",width:"80;",alt:"NixyJuppie"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Nixy")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/nrvo"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/151435968?u=e1dcb307fd0efdc45cddbe9490a7b956e4da6835&v=4",width:"80;",alt:"nrvo"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/mezza93"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/153599966?v=4",width:"80;",alt:"mezza93"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))))),(0,l.yg)("h2",{id:"contributors"},"Contributors"),(0,l.yg)("table",null,(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Lissy93"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1862727?v=4",width:"80;",alt:"Lissy93"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alicia Sykes")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/liss-bot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/87835202?v=4",width:"80;",alt:"liss-bot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alicia Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/marekful"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/10281476?v=4",width:"80;",alt:"marekful"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Marcell F\xfcl\xf6p")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/EVOTk"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/45015615?v=4",width:"80;",alt:"EVOTk"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"EVOTk")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/snyk-bot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/19733683?v=4",width:"80;",alt:"snyk-bot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Snyk Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/azerioxal"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5369885?v=4",width:"80;",alt:"azerioxal"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kenneth Church"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/m42e"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/2410802?v=4",width:"80;",alt:"m42e"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Matthias Bilger")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/CrazyWolf13"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/96661824?v=4",width:"80;",alt:"CrazyWolf13"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Tobias")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/pinarruiz"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/37040888?v=4",width:"80;",alt:"pinarruiz"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alejandro Pinar Ruiz")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/imjimmeh"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/2104997?v=4",width:"80;",alt:"imjimmeh"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/kashif-se"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5568138?v=4",width:"80;",alt:"kashif-se"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kashif Sohail")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/walkxcode"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/71191962?v=4",width:"80;",alt:"walkxcode"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Walkx"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/josuablejeru"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/37913833?v=4",width:"80;",alt:"josuablejeru"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Josua Blejeru ")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/evroon"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11857441?v=4",width:"80;",alt:"evroon"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Erik Vroon")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/jammo2k5"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/8106602?v=4",width:"80;",alt:"jammo2k5"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jammo2k5")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/lordpansar"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/14231148?v=4",width:"80;",alt:"lordpansar"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Magnus Sundstr\xf6m")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Cereal916"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7526937?v=4",width:"80;",alt:"Cereal916"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kristian Brasel")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/albcp"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/3170731?v=4",width:"80;",alt:"albcp"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alberto"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/altearius"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/270430?v=4",width:"80;",alt:"altearius"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Chris Nielsen")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/UrekD"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/38784343?v=4",width:"80;",alt:"UrekD"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"UrekD")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/wozboz"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/51856582?v=4",width:"80;",alt:"wozboz"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Totto16"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/32566573?v=4",width:"80;",alt:"Totto16"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Totto16")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/remygrandin"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1934515?v=4",width:"80;",alt:"remygrandin"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Remygrandin")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/DimitriDR"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/56969769?v=4",width:"80;",alt:"DimitriDR"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Dimitri"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Tracreed"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6306365?v=4",width:"80;",alt:"Tracreed"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"David Alasow")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/aviolaris"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/48277853?v=4",width:"80;",alt:"aviolaris"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Andreas Violaris")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/rubenandre"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/9402773?v=4",width:"80;",alt:"rubenandre"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"R\xfaben Silva")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/rtm516"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5401186?v=4",width:"80;",alt:"rtm516"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Rtm516")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/zcq100"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/425234?v=4",width:"80;",alt:"zcq100"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/onedr0p"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/213795?v=4",width:"80;",alt:"onedr0p"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"\u15ea\u0454\u03bd\u03b9\u03b7 \u15f7\u03c5\u043d\u029f"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/stanly0726"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/37040069?v=4",width:"80;",alt:"stanly0726"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Stanly0726")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Bogyie"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/82003678?v=4",width:"80;",alt:"Bogyie"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Bogyeong Kim")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Tuzi555"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/62188066?v=4",width:"80;",alt:"Tuzi555"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jakub Tuzar")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/berksmbl"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/10000339?v=4",width:"80;",alt:"berksmbl"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Berk S\xfcmb\xfcl")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alucarddelta"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/20882097?v=4",width:"80;",alt:"alucarddelta"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Brent")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/k073l"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/21180271?v=4",width:"80;",alt:"k073l"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/kt-alt"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/51970249?v=4",width:"80;",alt:"kt-alt"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/mmihaly"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/50031464?v=4",width:"80;",alt:"mmihaly"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/patrickheeney"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1407228?v=4",width:"80;",alt:"patrickheeney"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Patrick Heeney")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/rokiden"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11071229?v=4",width:"80;",alt:"rokiden"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Denis Kazimirov")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/ssrangisetti"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/46807508?v=4",width:"80;",alt:"ssrangisetti"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BySempron"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/15928132?v=4",width:"80;",alt:"BySempron"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Sergio"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/itsmejoeeey"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/9375730?v=4",width:"80;",alt:"itsmejoeeey"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Joey Miller")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/hockeymikey"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1435185?v=4",width:"80;",alt:"hockeymikey"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/thomaswienecke"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11446531?v=4",width:"80;",alt:"thomaswienecke"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Thomas Wienecke")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/deneor"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1063265?v=4",width:"80;",alt:"deneor"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/daentech"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/358678?v=4",width:"80;",alt:"daentech"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Dan Gilbert")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/moemoeq"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1808434?v=4",width:"80;",alt:"moemoeq"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"CHAIYEON CHO"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BOZG"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6022344?v=4",width:"80;",alt:"BOZG"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Stephen Rigney")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/a-mnich"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/56564725?v=4",width:"80;",alt:"a-mnich"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alexander Mnich")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alayham"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/518776?v=4",width:"80;",alt:"alayham"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Al-Ayham Saleh")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alexdelprete"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7027842?v=4",width:"80;",alt:"alexdelprete"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alessandro Del Prete")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/sachahjkl"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/32895534?v=4",width:"80;",alt:"sachahjkl"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Sacha")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/shazzx"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/131521332?v=4",width:"80;",alt:"shazzx"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Shazz"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/ThinkSalat"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/31082405?v=4",width:"80;",alt:"ThinkSalat"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Shawn Salat")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/royshreyaa"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/139828242?v=4",width:"80;",alt:"royshreyaa"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Smexhy"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/4880625?v=4",width:"80;",alt:"Smexhy"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/stavros-k"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/47820033?v=4",width:"80;",alt:"stavros-k"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Stavros Kois")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/XenonR"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/18627623?v=4",width:"80;",alt:"XenonR"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Steffen Schmidt")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/StevKast"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/17804308?v=4",width:"80;",alt:"StevKast"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Steven Kast"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/AmadeusGraves"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/18572939?v=4",width:"80;",alt:"AmadeusGraves"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"\xc1ngel Fern\xe1ndez S\xe1nchez")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/turnrye"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/701035?v=4",width:"80;",alt:"turnrye"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ryan Turner")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/rubjo"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/42270947?v=4",width:"80;",alt:"rubjo"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/PrynsTag"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/56314705?v=4",width:"80;",alt:"PrynsTag"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Prince Carl Velasco")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/PlusaN"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/61884717?v=4",width:"80;",alt:"PlusaN"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Andrey")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/oka4shi"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/67847553?v=4",width:"80;",alt:"oka4shi"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"OKAMOTO Shigehiro"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bubylou"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/3878640?v=4",width:"80;",alt:"bubylou"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Nicholas Malcolm")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/miclav"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11891522?v=4",width:"80;",alt:"miclav"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Michael Lavaire")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/imsakg"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/62212589?v=4",width:"80;",alt:"imsakg"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Mert Sefa AKGUN")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/ethan-hann"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/36464732?v=4",width:"80;",alt:"ethan-hann"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ethan Hann")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/tazboyz16"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/12215340?v=4",width:"80;",alt:"tazboyz16"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/sur1v"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/19678230?v=4",width:"80;",alt:"sur1v"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jos\xe9 Ignacio"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/soaibsafi"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11424812?v=4",width:"80;",alt:"soaibsafi"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Soaibuzzaman")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/pablomalo"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/25877142?v=4",width:"80;",alt:"pablomalo"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/markxoe"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/59475466?v=4",width:"80;",alt:"markxoe"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Mark Oude Elberink")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/lxjv"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/63261955?v=4",width:"80;",alt:"lxjv"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Laker Turner")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/kxenoxx"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/9744900?v=4",width:"80;",alt:"kxenoxx"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kxenox")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/jrobles98"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/30221842?v=4",width:"80;",alt:"jrobles98"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/jnach"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/33467747?v=4",width:"80;",alt:"jnach"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jnach")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/imlonghao"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/4951333?v=4",width:"80;",alt:"imlonghao"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Imlonghao")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/icy-comet"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/50461557?v=4",width:"80;",alt:"icy-comet"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Aniket Teredesai")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/huangshaohuai"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/24775925?v=4",width:"80;",alt:"huangshaohuai"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/flechaig"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/10887132?v=4",width:"80;",alt:"flechaig"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dr460nf1r3"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/12834713?v=4",width:"80;",alt:"dr460nf1r3"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Nico"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/baifengheixi"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/98794233?v=4",width:"80;",alt:"baifengheixi"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/allozavrr"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/63748214?v=4",width:"80;",alt:"allozavrr"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/XertDev"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/16572811?v=4",width:"80;",alt:"XertDev"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Xert")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/emiran-orange"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/71817149?v=4",width:"80;",alt:"emiran-orange"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/edugof"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/19559978?v=4",width:"80;",alt:"edugof"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Eduardo Gomez")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Dylan-Bs"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/35694107?v=4",width:"80;",alt:"Dylan-Bs"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Dylan Bersans"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dougaldhub"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/25713235?v=4",width:"80;",alt:"dougaldhub"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Doug Lock")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dkyeremeh"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/52928432?v=4",width:"80;",alt:"dkyeremeh"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Desmond Kyeremeh")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/deepsourcebot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/60907429?v=4",width:"80;",alt:"deepsourcebot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"DeepSource Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/DawidPietrykowski"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/53954695?v=4",width:"80;",alt:"DawidPietrykowski"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/skaarj1989"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/34756939?v=4",width:"80;",alt:"skaarj1989"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"David")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/clsty"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/129247596?v=4",width:"80;",alt:"clsty"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Celestial.y"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bskim45"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5674934?v=4",width:"80;",alt:"bskim45"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Bumsoo Kim")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BhasherBEL"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/45831883?v=4",width:"80;",alt:"BhasherBEL"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Brieuc Dubois")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BeginCI"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/57495754?v=4",width:"80;",alt:"BeginCI"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Begin")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BRAVO68WEB"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/41448663?v=4",width:"80;",alt:"BRAVO68WEB"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jyotirmoy Bandyopadhyaya [Bravo68]")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/AaronPorts"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/32810520?v=4",width:"80;",alt:"AaronPorts"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Artyom")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alydemah"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/652035?v=4",width:"80;",alt:"alydemah"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Aly Mohamed"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/5idereal"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/30827929?v=4",width:"80;",alt:"5idereal"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"5idereal")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/0n1cOn3"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/27576311?v=4",width:"80;",alt:"0n1cOn3"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"0n1cOn3")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/maximemoreillon"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/29086128?v=4",width:"80;",alt:"maximemoreillon"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Maxime Moreillon")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Glitch3dPenguin"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/3271160?v=4",width:"80;",alt:"Glitch3dPenguin"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Max Kulik")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/markusdd"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/25175069?v=4",width:"80;",alt:"markusdd"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Markus Krause")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/asenov"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/280619?v=4",width:"80;",alt:"asenov"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"\u041c\u0438\u0440\u043e\u0441\u043b\u0430\u0432 \u0410\u0441\u0435\u043d\u043e\u0432"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/luispabon"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6388823?v=4",width:"80;",alt:"luispabon"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Luis Pabon")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/LeoColman"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1577251?v=4",width:"80;",alt:"LeoColman"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Leonardo Colman Lopes")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/KierenConnell"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/46445781?v=4",width:"80;",alt:"KierenConnell"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kieren Connell")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/kieraneglin"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/569917?v=4",width:"80;",alt:"kieraneglin"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kieran")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Singebob"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/24290044?v=4",width:"80;",alt:"Singebob"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jeremy Chauvin")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Hellhium"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11504877?v=4",width:"80;",alt:"Hellhium"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jemy SCHNEPP"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/jjmung"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6049600?v=4",width:"80;",alt:"jjmung"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"JJ Munguia")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/b1thunt3r"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/791091?v=4",width:"80;",alt:"b1thunt3r"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ishan Jain")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Compunctus"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5058853?v=4",width:"80;",alt:"Compunctus"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Iaroslav Dronskii")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/nealian"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/865115?v=4",width:"80;",alt:"nealian"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ian Neal")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/FraglyG"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/56320839?v=4",width:"80;",alt:"FraglyG"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Hendrik Strydom")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/hubortje"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/62364169?v=4",width:"80;",alt:"hubortje"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Harald T\xf6pfer"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/gbrown09"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/3360055?v=4",width:"80;",alt:"gbrown09"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Garrett Brown")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/FormatToday"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/20515769?v=4",width:"80;",alt:"FormatToday"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"FormatToday")))))),(0,l.yg)("h2",{id:"helpful-users"},"Helpful Users"),(0,l.yg)("table",null,(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/evotk"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/45015615?v=4",width:"80;",alt:"evotk"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Evotk")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/shadowking001"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/43928955?v=4",width:"80;",alt:"shadowking001"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"LawrenceP.")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/urekd"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/38784343?v=4",width:"80;",alt:"urekd"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Urekd")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dylanbeme"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/41838333?v=4",width:"80;",alt:"dylanbeme"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"DylanH")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/milesteg1"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/29298312?v=4",width:"80;",alt:"milesteg1"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Milesteg1")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/lu4t"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/29571529?v=4",width:"80;",alt:"lu4t"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Lu4t")))))),(0,l.yg)("h2",{id:"bots"},"Bots"),(0,l.yg)("table",null,(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/liss-bot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/87835202?v=4",width:"80;",alt:"liss-bot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alicia Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/snyk-bot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/19733683?v=4",width:"80;",alt:"snyk-bot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Snyk Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/netlify"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7892489?v=4",width:"80;",alt:"netlify"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Netlify")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/viezly"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/78649443?v=4",width:"80;",alt:"viezly"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Viezly")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/muse-dev"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/42072939?v=4",width:"80;",alt:"muse-dev"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"MuseDev")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/github-actions[bot]"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/in/15368?v=4",width:"80;",alt:"github-actions[bot]"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"github-actions[bot]"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dependabot[bot]"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/in/29110?v=4",width:"80;",alt:"dependabot[bot]"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"dependabot[bot]")))))),(0,l.yg)("blockquote",null,(0,l.yg)("p",{parentName:"blockquote"},"The above section is auto-generated, using ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/marketplace/actions/contribute-list"},"contribute-list")," by @akhilmhdh.")),(0,l.yg)("h2",{id:"newest-stargazers"},"Newest Stargazers"),(0,l.yg)("p",null,(0,l.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/stargazers"},(0,l.yg)("img",{parentName:"a",src:"https://reporoster.com/stars/dark/Lissy93/dashy",alt:"Recent Star Gazers"}))),(0,l.yg)("p",null,(0,l.yg)("a",{parentName:"p",href:"https://github.com/lissy93/dashy/network/members"},(0,l.yg)("img",{parentName:"a",src:"https://reporoster.com/forks/dark/lissy93/dashy",alt:"Recent Forkers"}))),(0,l.yg)("hr",null),(0,l.yg)("h2",{id:"dependencies"},"Dependencies"),(0,l.yg)("p",null,"This app definitely wouldn't have been quite so possible without the making use of the following package and components. Full credit and big kudos to their respective authors, who've done an amazing job in building and maintaining them. For a full breakdown of dependency licenses, please see ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/.github/LEGAL.md"},"Legal")),(0,l.yg)("h3",{id:"core"},"Core"),(0,l.yg)("p",null,"At it's core, the application uses ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/vuejs/vue"},(0,l.yg)("strong",{parentName:"a"},"Vue.js")),", as well as it's services with ",(0,l.yg)("a",{parentName:"p",href:"https://vuex.vuejs.org/"},(0,l.yg)("strong",{parentName:"a"},"VueX"))," for state management. Styling is done with ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/sass/sass"},(0,l.yg)("strong",{parentName:"a"},"SCSS")),", JavaScript is currently ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/babel/babel"},(0,l.yg)("strong",{parentName:"a"},"Babel")),", (but I am in the process of converting to ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/Microsoft/TypeScript"},(0,l.yg)("strong",{parentName:"a"},"TypeScript")),"). Linting is done with ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/eslint/eslint"},(0,l.yg)("strong",{parentName:"a"},"ESLint"))," and ",(0,l.yg)("a",{parentName:"p",href:"https://prettier.io/"},(0,l.yg)("strong",{parentName:"a"},"Prettier")),", both following the ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/airbnb/javascript"},(0,l.yg)("strong",{parentName:"a"},"AirBnB Styleguide")),". The config is defined in ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/yaml/yaml"},(0,l.yg)("strong",{parentName:"a"},"YAML")),", with a simple ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/nodejs/node"},(0,l.yg)("strong",{parentName:"a"},"Node.js"))," server to serve up the static app and the optional API endpoints, and container deployment is done with ",(0,l.yg)("a",{parentName:"p",href:"https://www.docker.com/"},(0,l.yg)("strong",{parentName:"a"},"Docker")),"."),(0,l.yg)("h3",{id:"utilities"},"Utilities"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/brix/crypto-js"},(0,l.yg)("inlineCode",{parentName:"a"},"crypto-js"))," - Encryption implementations by @evanvosberg and community ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/axios/axios"},(0,l.yg)("inlineCode",{parentName:"a"},"axios"))," - Promise based HTTP client by @mzabriskie and community ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/ajv-validator/ajv"},(0,l.yg)("inlineCode",{parentName:"a"},"ajv"))," - JSON schema Validator by @epoberezkin and community ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/kazupon/vue-i18n"},(0,l.yg)("inlineCode",{parentName:"a"},"i18n"))," - Internationalization plugin by @kazupon and community ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/frappe/charts"},(0,l.yg)("inlineCode",{parentName:"a"},"frappe-charts"))," - Lightweight charting library by @frappe ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT"))),(0,l.yg)("h3",{id:"frontend-components"},"Frontend Components"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/sagalbot/vue-select"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-select"))," - Dropdown component by @sagalbot ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/euvl/vue-js-modal"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-js-modal"))," - Modal component by @euvl ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/Akryum/v-tooltip"},(0,l.yg)("inlineCode",{parentName:"a"},"v-tooltip"))," - Tooltip component by @Akryum ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/jairoblatt/vue-material-tabs"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-material-tabs"))," - Tab view component by @jairoblatt ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/yansenlei/VJsoneditor"},(0,l.yg)("inlineCode",{parentName:"a"},"VJsoneditor"))," - Interactive JSON editor component by @yansenlei ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT"),(0,l.yg)("ul",{parentName:"li"},(0,l.yg)("li",{parentName:"ul"},"Forked from ",(0,l.yg)("a",{parentName:"li",href:"https://github.com/josdejong/jsoneditor"},(0,l.yg)("inlineCode",{parentName:"a"},"JsonEditor"))," by @josdejong ",(0,l.yg)("inlineCode",{parentName:"li"},"Apache-2.0 License")))),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/shakee93/vue-toasted"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-toasted"))," - Toast notification component by @shakee93 ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/saintplay/vue-swatches"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-swatches"))," - Color palete picker by @saintplay ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT"))),(0,l.yg)("h3",{id:"backup--sync-server"},"Backup & Sync Server"),(0,l.yg)("p",null,"Although the app is purely frontend, there is an optional cloud sync feature, for off-site backup and restore. This is built as a serverless function on ",(0,l.yg)("a",{parentName:"p",href:"https://workers.cloudflare.com/"},"Cloudflare workers")," using ",(0,l.yg)("a",{parentName:"p",href:"https://developers.cloudflare.com/workers/runtime-apis/kv"},"KV")," and ",(0,l.yg)("a",{parentName:"p",href:"https://developers.cloudflare.com/workers/runtime-apis/web-crypto"},"web crypto")),(0,l.yg)("h3",{id:"external-services"},"External Services"),(0,l.yg)("p",null,"The 1-Click deploy demo uses ",(0,l.yg)("a",{parentName:"p",href:"https://play-with-docker.com/"},"Play-with-Docker Labs"),". Code is hosted on ",(0,l.yg)("a",{parentName:"p",href:"https://github.com"},"GitHub"),", Docker images are hosted on ",(0,l.yg)("a",{parentName:"p",href:"https://hub.docker.com/"},"DockerHub"),", and the demos are hosted on ",(0,l.yg)("a",{parentName:"p",href:"https://www.netlify.com/"},"Netlify"),"."),(0,l.yg)("h3",{id:"actions"},"Actions"),(0,l.yg)("p",null,"This repo makes heavy use of ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/features/actions"},"GitHub actions")," to run automated workflows. The following base actions are totally awesome, and have been extremely useful. Full credit to their respective authors"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/butlerlogic/action-autotag"},(0,l.yg)("inlineCode",{parentName:"a"},"action-autotag"))," by @butlerlogic - Tags new versions when app version changes"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/joeizzard/action-wiki-sync"},(0,l.yg)("inlineCode",{parentName:"a"},"action-wiki-sync"))," by @joeizzard - Copies the markdown docs to the GH wiki"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/bubkoo/contributors-list"},(0,l.yg)("inlineCode",{parentName:"a"},"contributors-list"))," by @bubkoo - Generates contributors SVG"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/akhilmhdh/contributors-readme-action"},(0,l.yg)("inlineCode",{parentName:"a"},"contributors-readme-action"))," by @akhilmhdh - Inserts contributors into credits"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/eter-evans/create-pull-request"},(0,l.yg)("inlineCode",{parentName:"a"},"create-pull-request"))," by @eter-evans - Creates pull request"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/JamesIves/github-pages-deploy-action"},(0,l.yg)("inlineCode",{parentName:"a"},"github-pages-deploy-action"))," by @JamesIves - Deploy app to GH pages"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/apexskier/github-release-commenter"},(0,l.yg)("inlineCode",{parentName:"a"},"github-release-commenter"))," by @apexskier - Updates issues when fix is released"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/JamesIves/github-sponsors-readme-action"},(0,l.yg)("inlineCode",{parentName:"a"},"github-sponsors-readme-action"))," by @JamesIves - Inserts sponsors into credits"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/JasonEtco/is-sponsor-label-action"},(0,l.yg)("inlineCode",{parentName:"a"},"is-sponsor-label-action"))," by @JasonEtco - Label sponsors, for priority support"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/tomsun28/issues-translate-action"},(0,l.yg)("inlineCode",{parentName:"a"},"issues-translate-action"))," by @tomsun28 - Translates non-English issues and comments"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/sobolevn/misspell-fixer-action"},(0,l.yg)("inlineCode",{parentName:"a"},"misspell-fixer-action"))," by @sobolevn - Finds and fixes typos"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/uhyo/please-star-first"},(0,l.yg)("inlineCode",{parentName:"a"},"please-star-first"))," by @uhyo - Closes certain issues by non-stargazers"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/exercism/pr-commenter-action"},(0,l.yg)("inlineCode",{parentName:"a"},"pr-commenter-action"))," by @exercism - Adds info comments to PR based on the files changed"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/snyk/actions/node"},(0,l.yg)("inlineCode",{parentName:"a"},"snyk note"))," by @snyk - Reports vulnerabilities in the code or dependencies"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/alstr/todo-to-issue-action"},(0,l.yg)("inlineCode",{parentName:"a"},"todo-to-issue-action"))," by @alstr - Opens issues from todos in the code"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/Simek/yarn-lock-changes"},(0,l.yg)("inlineCode",{parentName:"a"},"yarn-lock-changes"))," by @Simek - Outputs dependency changes in PR")),(0,l.yg)("hr",null),(0,l.yg)("h2",{id:"you"},"You"),(0,l.yg)("p",null,"Would you like to be listed here? Whatever your skill set, Dashy needs people like you to help support future development. Check out the ",(0,l.yg)("a",{parentName:"p",href:"/docs/contributing"},"Contributing Page")," for ways that you can get involved. Huge thank you to everyone who has already contributed! \ud83d\udc96"))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/18ba09e8.e467166a.js b/assets/js/18ba09e8.e467166a.js deleted file mode 100644 index 8c666938..00000000 --- a/assets/js/18ba09e8.e467166a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[849],{5680:(t,e,a)=>{a.d(e,{xA:()=>y,yg:()=>b});var n=a(6540);function l(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function g(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function r(t){for(var e=1;e=0||(l[a]=t[a]);return l}(t,e);if(Object.getOwnPropertySymbols){var g=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(l[a]=t[a])}return l}var i=n.createContext({}),s=function(t){var e=n.useContext(i),a=e;return t&&(a="function"==typeof t?t(e):r(r({},e),t)),a},y=function(t){var e=s(t.components);return n.createElement(i.Provider,{value:e},t.children)},h="mdxType",o={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},c=n.forwardRef((function(t,e){var a=t.components,l=t.mdxType,g=t.originalType,i=t.parentName,y=u(t,["components","mdxType","originalType","parentName"]),h=s(a),c=l,b=h["".concat(i,".").concat(c)]||h[c]||o[c]||g;return a?n.createElement(b,r(r({ref:e},y),{},{components:a})):n.createElement(b,r({ref:e},y))}));function b(t,e){var a=arguments,l=e&&e.mdxType;if("string"==typeof t||l){var g=a.length,r=new Array(g);r[0]=c;var u={};for(var i in e)hasOwnProperty.call(e,i)&&(u[i]=e[i]);u.originalType=t,u[h]="string"==typeof t?t:l,r[1]=u;for(var s=2;s{a.r(e),a.d(e,{contentTitle:()=>r,default:()=>h,frontMatter:()=>g,metadata:()=>u,toc:()=>i});var n=a(8168),l=(a(6540),a(5680));const g={},r="Credits",u={unversionedId:"credits",id:"credits",isDocsHomePage:!1,title:"Credits",description:"Sponsors",source:"@site/docs/credits.md",sourceDirName:".",slug:"/credits",permalink:"/docs/credits",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/credits.md",version:"current",frontMatter:{}},i=[{value:"Sponsors",id:"sponsors",children:[]},{value:"Contributors",id:"contributors",children:[]},{value:"Helpful Users",id:"helpful-users",children:[]},{value:"Bots",id:"bots",children:[]},{value:"Newest Stargazers",id:"newest-stargazers",children:[]},{value:"Dependencies",id:"dependencies",children:[{value:"Core",id:"core",children:[]},{value:"Utilities",id:"utilities",children:[]},{value:"Frontend Components",id:"frontend-components",children:[]},{value:"Backup & Sync Server",id:"backup--sync-server",children:[]},{value:"External Services",id:"external-services",children:[]},{value:"Actions",id:"actions",children:[]}]},{value:"You",id:"you",children:[]}],s={toc:i},y="wrapper";function h(t){let{components:e,...a}=t;return(0,l.yg)(y,(0,n.A)({},s,a,{components:e,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"credits"},"Credits"),(0,l.yg)("h2",{id:"sponsors"},"Sponsors"),(0,l.yg)("table",null,(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/koconder"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/25068?u=582657b23622aaa3dfe68bd028a780f272f456fa&v=4",width:"80;",alt:"koconder"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Vincent Koc")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/peng1can"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/225854?v=4",width:"80;",alt:"peng1can"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alydemah"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/652035?u=ac2c04e474da37bfeafcfa25076cc1800997aedb&v=4",width:"80;",alt:"alydemah"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Aly Mohamed")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bgadrian"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/830001?v=4",width:"80;",alt:"bgadrian"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"B.G.Adrian")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/tbjers"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1117052?u=539d96d5e581b3139c75713ce35b89a36626404c&v=4",width:"80;",alt:"tbjers"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Torgny Bjers")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/emlazzarin"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1141361?u=714e3487a3f2e0df721b01a0133945f075d3ff68&v=4",width:"80;",alt:"emlazzarin"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Eddy Lazzarin"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/AnandChowdhary"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/2841780?u=747e554b3a7f12eb20b7910e1c87d817844f714f&v=4",width:"80;",alt:"AnandChowdhary"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Anand Chowdhary")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/shrippen"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/2873570?v=4",width:"80;",alt:"shrippen"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bile0026"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5022496?u=aec96ad173c0ea9baaba93807efa8a848af6595c&v=4",width:"80;",alt:"bile0026"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Zach Biles")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/UlisesGascon"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5110813?u=3c41facd8aa26154b9451de237c34b0f78d672a5&v=4",width:"80;",alt:"UlisesGascon"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ulises Gasc\xf3n")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/digitalarche"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6546135?u=d033c9c16e8367987aec3f9ff5922bc67dd1eedf&v=4",width:"80;",alt:"digitalarche"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Digital Archeology")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/InDieTasten"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7047377?v=4",width:"80;",alt:"InDieTasten"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bmcgonag"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7346620?u=2a0f9284f3e12ac1cc15288c254d1ec68a5081e8&v=4",width:"80;",alt:"bmcgonag"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Brian McGonagill")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/vlad-timofeev"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11474041?u=eee43705b54d2ec9f51fc4fcce5ad18dd17c87e4&v=4",width:"80;",alt:"vlad-timofeev"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Vlad Timofeev")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/helixzz"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/12218889?u=d06d0c103dfbdb99450623064f7da3c5a3675fb6&v=4",width:"80;",alt:"helixzz"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"HeliXZz")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/forwardemail"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/32481436?v=4",width:"80;",alt:"forwardemail"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Forward Email - Open-source & Privacy-focused Email Service (2023)")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Bastii717"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/53431819?u=604977bed6ad6875ada890d0d3765a4cacc2fa14&v=4",width:"80;",alt:"Bastii717"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/frankdez93"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/87549420?v=4",width:"80;",alt:"frankdez93"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/ratty222"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/92832598?u=137b65530cbd5f5af9c24cde51baa6cc77cc934b&v=4",width:"80;",alt:"ratty222"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ratty222")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/hernanpopper"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/104868017?v=4",width:"80;",alt:"hernanpopper"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/NixyJuppie"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/138570196?u=b102c222487905728b858704962d32759df29ebe&v=4",width:"80;",alt:"NixyJuppie"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Nixy")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/nrvo"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/151435968?u=e1dcb307fd0efdc45cddbe9490a7b956e4da6835&v=4",width:"80;",alt:"nrvo"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/mezza93"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/153599966?v=4",width:"80;",alt:"mezza93"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))))),(0,l.yg)("h2",{id:"contributors"},"Contributors"),(0,l.yg)("table",null,(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Lissy93"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1862727?v=4",width:"80;",alt:"Lissy93"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alicia Sykes")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/liss-bot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/87835202?v=4",width:"80;",alt:"liss-bot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alicia Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/marekful"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/10281476?v=4",width:"80;",alt:"marekful"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Marcell F\xfcl\xf6p")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/EVOTk"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/45015615?v=4",width:"80;",alt:"EVOTk"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"EVOTk")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/snyk-bot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/19733683?v=4",width:"80;",alt:"snyk-bot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Snyk Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/azerioxal"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5369885?v=4",width:"80;",alt:"azerioxal"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kenneth Church"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/m42e"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/2410802?v=4",width:"80;",alt:"m42e"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Matthias Bilger")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/pinarruiz"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/37040888?v=4",width:"80;",alt:"pinarruiz"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alejandro Pinar Ruiz")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/CrazyWolf13"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/96661824?v=4",width:"80;",alt:"CrazyWolf13"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Tobias")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/kashif-se"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5568138?v=4",width:"80;",alt:"kashif-se"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kashif Sohail")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/josuablejeru"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/37913833?v=4",width:"80;",alt:"josuablejeru"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Josua Blejeru ")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/walkxcode"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/71191962?v=4",width:"80;",alt:"walkxcode"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Walkx"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/evroon"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11857441?v=4",width:"80;",alt:"evroon"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Erik Vroon")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/jammo2k5"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/8106602?v=4",width:"80;",alt:"jammo2k5"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jammo2k5")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/lordpansar"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/14231148?v=4",width:"80;",alt:"lordpansar"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Magnus Sundstr\xf6m")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Cereal916"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7526937?v=4",width:"80;",alt:"Cereal916"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kristian Brasel")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/albcp"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/3170731?v=4",width:"80;",alt:"albcp"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alberto")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/altearius"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/270430?v=4",width:"80;",alt:"altearius"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Chris Nielsen"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/UrekD"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/38784343?v=4",width:"80;",alt:"UrekD"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"UrekD")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/wozboz"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/51856582?v=4",width:"80;",alt:"wozboz"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Totto16"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/32566573?v=4",width:"80;",alt:"Totto16"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Totto16")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/remygrandin"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1934515?v=4",width:"80;",alt:"remygrandin"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Remygrandin")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/DimitriDR"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/56969769?v=4",width:"80;",alt:"DimitriDR"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Dimitri")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Tracreed"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6306365?v=4",width:"80;",alt:"Tracreed"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"David Alasow"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/aviolaris"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/48277853?v=4",width:"80;",alt:"aviolaris"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Andreas Violaris")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/rubenandre"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/9402773?v=4",width:"80;",alt:"rubenandre"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"R\xfaben Silva")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/rtm516"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5401186?v=4",width:"80;",alt:"rtm516"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Rtm516")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/zcq100"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/425234?v=4",width:"80;",alt:"zcq100"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/onedr0p"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/213795?v=4",width:"80;",alt:"onedr0p"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"\u15ea\u0454\u03bd\u03b9\u03b7 \u15f7\u03c5\u043d\u029f")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/stanly0726"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/37040069?v=4",width:"80;",alt:"stanly0726"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Stanly0726"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Bogyie"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/82003678?v=4",width:"80;",alt:"Bogyie"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Bogyeong Kim")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Tuzi555"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/62188066?v=4",width:"80;",alt:"Tuzi555"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jakub Tuzar")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/berksmbl"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/10000339?v=4",width:"80;",alt:"berksmbl"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Berk S\xfcmb\xfcl")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alucarddelta"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/20882097?v=4",width:"80;",alt:"alucarddelta"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Brent")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/k073l"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/21180271?v=4",width:"80;",alt:"k073l"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/kt-alt"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/51970249?v=4",width:"80;",alt:"kt-alt"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/mmihaly"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/50031464?v=4",width:"80;",alt:"mmihaly"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/patrickheeney"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1407228?v=4",width:"80;",alt:"patrickheeney"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Patrick Heeney")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/rokiden"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11071229?v=4",width:"80;",alt:"rokiden"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Denis Kazimirov")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/ssrangisetti"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/46807508?v=4",width:"80;",alt:"ssrangisetti"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BySempron"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/15928132?v=4",width:"80;",alt:"BySempron"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Sergio")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/itsmejoeeey"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/9375730?v=4",width:"80;",alt:"itsmejoeeey"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Joey Miller"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/hockeymikey"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1435185?v=4",width:"80;",alt:"hockeymikey"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/thomaswienecke"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11446531?v=4",width:"80;",alt:"thomaswienecke"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Thomas Wienecke")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/deneor"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1063265?v=4",width:"80;",alt:"deneor"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/daentech"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/358678?v=4",width:"80;",alt:"daentech"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Dan Gilbert")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/moemoeq"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1808434?v=4",width:"80;",alt:"moemoeq"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"CHAIYEON CHO")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BOZG"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6022344?v=4",width:"80;",alt:"BOZG"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Stephen Rigney"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/a-mnich"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/56564725?v=4",width:"80;",alt:"a-mnich"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alexander Mnich")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alayham"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/518776?v=4",width:"80;",alt:"alayham"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Al-Ayham Saleh")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alexdelprete"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7027842?v=4",width:"80;",alt:"alexdelprete"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alessandro Del Prete")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/sachahjkl"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/32895534?v=4",width:"80;",alt:"sachahjkl"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Sacha")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/shazzx"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/131521332?v=4",width:"80;",alt:"shazzx"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Shazz")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/ThinkSalat"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/31082405?v=4",width:"80;",alt:"ThinkSalat"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Shawn Salat"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/royshreyaa"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/139828242?v=4",width:"80;",alt:"royshreyaa"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Smexhy"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/4880625?v=4",width:"80;",alt:"Smexhy"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/stavros-k"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/47820033?v=4",width:"80;",alt:"stavros-k"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Stavros Kois")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/XenonR"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/18627623?v=4",width:"80;",alt:"XenonR"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Steffen Schmidt")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/StevKast"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/17804308?v=4",width:"80;",alt:"StevKast"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Steven Kast")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/AmadeusGraves"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/18572939?v=4",width:"80;",alt:"AmadeusGraves"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"\xc1ngel Fern\xe1ndez S\xe1nchez"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/turnrye"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/701035?v=4",width:"80;",alt:"turnrye"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ryan Turner")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/rubjo"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/42270947?v=4",width:"80;",alt:"rubjo"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/PrynsTag"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/56314705?v=4",width:"80;",alt:"PrynsTag"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Prince Carl Velasco")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/PlusaN"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/61884717?v=4",width:"80;",alt:"PlusaN"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Andrey")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/oka4shi"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/67847553?v=4",width:"80;",alt:"oka4shi"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"OKAMOTO Shigehiro")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bubylou"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/3878640?v=4",width:"80;",alt:"bubylou"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Nicholas Malcolm"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/miclav"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11891522?v=4",width:"80;",alt:"miclav"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Michael Lavaire")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/imsakg"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/62212589?v=4",width:"80;",alt:"imsakg"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Mert Sefa AKGUN")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/ethan-hann"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/36464732?v=4",width:"80;",alt:"ethan-hann"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ethan Hann")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/tazboyz16"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/12215340?v=4",width:"80;",alt:"tazboyz16"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/sur1v"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/19678230?v=4",width:"80;",alt:"sur1v"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jos\xe9 Ignacio")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/soaibsafi"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11424812?v=4",width:"80;",alt:"soaibsafi"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Soaibuzzaman"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/pablomalo"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/25877142?v=4",width:"80;",alt:"pablomalo"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/markxoe"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/59475466?v=4",width:"80;",alt:"markxoe"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Mark Oude Elberink")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/lxjv"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/63261955?v=4",width:"80;",alt:"lxjv"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Laker Turner")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/kxenoxx"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/9744900?v=4",width:"80;",alt:"kxenoxx"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kxenox")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/jrobles98"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/30221842?v=4",width:"80;",alt:"jrobles98"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/jnach"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/33467747?v=4",width:"80;",alt:"jnach"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jnach"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/imlonghao"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/4951333?v=4",width:"80;",alt:"imlonghao"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Imlonghao")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/icy-comet"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/50461557?v=4",width:"80;",alt:"icy-comet"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Aniket Teredesai")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/huangshaohuai"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/24775925?v=4",width:"80;",alt:"huangshaohuai"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/flechaig"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/10887132?v=4",width:"80;",alt:"flechaig"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dr460nf1r3"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/12834713?v=4",width:"80;",alt:"dr460nf1r3"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Nico")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/baifengheixi"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/98794233?v=4",width:"80;",alt:"baifengheixi"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/allozavrr"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/63748214?v=4",width:"80;",alt:"allozavrr"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/XertDev"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/16572811?v=4",width:"80;",alt:"XertDev"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Xert")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/emiran-orange"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/71817149?v=4",width:"80;",alt:"emiran-orange"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/edugof"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/19559978?v=4",width:"80;",alt:"edugof"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Eduardo Gomez")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Dylan-Bs"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/35694107?v=4",width:"80;",alt:"Dylan-Bs"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Dylan Bersans")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dougaldhub"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/25713235?v=4",width:"80;",alt:"dougaldhub"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Doug Lock"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dkyeremeh"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/52928432?v=4",width:"80;",alt:"dkyeremeh"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Desmond Kyeremeh")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/deepsourcebot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/60907429?v=4",width:"80;",alt:"deepsourcebot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"DeepSource Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/DawidPietrykowski"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/53954695?v=4",width:"80;",alt:"DawidPietrykowski"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Null")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/skaarj1989"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/34756939?v=4",width:"80;",alt:"skaarj1989"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"David")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/clsty"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/129247596?v=4",width:"80;",alt:"clsty"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Celestial.y")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/bskim45"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5674934?v=4",width:"80;",alt:"bskim45"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Bumsoo Kim"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BhasherBEL"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/45831883?v=4",width:"80;",alt:"BhasherBEL"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Brieuc Dubois")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BeginCI"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/57495754?v=4",width:"80;",alt:"BeginCI"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Begin")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/BRAVO68WEB"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/41448663?v=4",width:"80;",alt:"BRAVO68WEB"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jyotirmoy Bandyopadhyaya [Bravo68]")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/AaronPorts"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/32810520?v=4",width:"80;",alt:"AaronPorts"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Artyom")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/alydemah"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/652035?v=4",width:"80;",alt:"alydemah"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Aly Mohamed")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/5idereal"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/30827929?v=4",width:"80;",alt:"5idereal"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"5idereal"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/0n1cOn3"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/27576311?v=4",width:"80;",alt:"0n1cOn3"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"0n1cOn3")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/maximemoreillon"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/29086128?v=4",width:"80;",alt:"maximemoreillon"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Maxime Moreillon")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Glitch3dPenguin"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/3271160?v=4",width:"80;",alt:"Glitch3dPenguin"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Max Kulik")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/markusdd"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/25175069?v=4",width:"80;",alt:"markusdd"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Markus Krause")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/asenov"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/280619?v=4",width:"80;",alt:"asenov"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"\u041c\u0438\u0440\u043e\u0441\u043b\u0430\u0432 \u0410\u0441\u0435\u043d\u043e\u0432")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/luispabon"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6388823?v=4",width:"80;",alt:"luispabon"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Luis Pabon"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/LeoColman"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/1577251?v=4",width:"80;",alt:"LeoColman"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Leonardo Colman Lopes")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/KierenConnell"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/46445781?v=4",width:"80;",alt:"KierenConnell"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kieren Connell")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/kieraneglin"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/569917?v=4",width:"80;",alt:"kieraneglin"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Kieran")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Singebob"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/24290044?v=4",width:"80;",alt:"Singebob"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jeremy Chauvin")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Hellhium"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/11504877?v=4",width:"80;",alt:"Hellhium"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Jemy SCHNEPP")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/jjmung"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/6049600?v=4",width:"80;",alt:"jjmung"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"JJ Munguia"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/b1thunt3r"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/791091?v=4",width:"80;",alt:"b1thunt3r"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ishan Jain")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/Compunctus"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/5058853?v=4",width:"80;",alt:"Compunctus"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Iaroslav Dronskii")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/nealian"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/865115?v=4",width:"80;",alt:"nealian"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Ian Neal")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/FraglyG"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/56320839?v=4",width:"80;",alt:"FraglyG"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Hendrik Strydom")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/hubortje"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/62364169?v=4",width:"80;",alt:"hubortje"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Harald T\xf6pfer")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/gbrown09"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/3360055?v=4",width:"80;",alt:"gbrown09"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Garrett Brown"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/FormatToday"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/20515769?v=4",width:"80;",alt:"FormatToday"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"FormatToday")))))),(0,l.yg)("h2",{id:"helpful-users"},"Helpful Users"),(0,l.yg)("table",null,(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/evotk"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/45015615?v=4",width:"80;",alt:"evotk"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Evotk")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/shadowking001"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/43928955?v=4",width:"80;",alt:"shadowking001"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"LawrenceP.")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/urekd"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/38784343?v=4",width:"80;",alt:"urekd"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Urekd")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dylanbeme"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/41838333?v=4",width:"80;",alt:"dylanbeme"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"DylanH")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/milesteg1"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/29298312?v=4",width:"80;",alt:"milesteg1"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Milesteg1")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/lu4t"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/29571529?v=4",width:"80;",alt:"lu4t"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Lu4t")))))),(0,l.yg)("h2",{id:"bots"},"Bots"),(0,l.yg)("table",null,(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/liss-bot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/87835202?v=4",width:"80;",alt:"liss-bot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Alicia Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/snyk-bot"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/19733683?v=4",width:"80;",alt:"snyk-bot"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Snyk Bot")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/netlify"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/7892489?v=4",width:"80;",alt:"netlify"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Netlify")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/viezly"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/78649443?v=4",width:"80;",alt:"viezly"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"Viezly")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/muse-dev"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/u/42072939?v=4",width:"80;",alt:"muse-dev"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"MuseDev")))),(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/github-actions[bot]"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/in/15368?v=4",width:"80;",alt:"github-actions[bot]"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"github-actions[bot]"))))),(0,l.yg)("tr",null,(0,l.yg)("td",{align:"center"},(0,l.yg)("a",{href:"https://github.com/dependabot[bot]"},(0,l.yg)("img",{src:"https://avatars.githubusercontent.com/in/29110?v=4",width:"80;",alt:"dependabot[bot]"}),(0,l.yg)("br",null),(0,l.yg)("sub",null,(0,l.yg)("b",null,"dependabot[bot]")))))),(0,l.yg)("blockquote",null,(0,l.yg)("p",{parentName:"blockquote"},"The above section is auto-generated, using ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/marketplace/actions/contribute-list"},"contribute-list")," by @akhilmhdh.")),(0,l.yg)("h2",{id:"newest-stargazers"},"Newest Stargazers"),(0,l.yg)("p",null,(0,l.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/stargazers"},(0,l.yg)("img",{parentName:"a",src:"https://reporoster.com/stars/dark/Lissy93/dashy",alt:"Recent Star Gazers"}))),(0,l.yg)("p",null,(0,l.yg)("a",{parentName:"p",href:"https://github.com/lissy93/dashy/network/members"},(0,l.yg)("img",{parentName:"a",src:"https://reporoster.com/forks/dark/lissy93/dashy",alt:"Recent Forkers"}))),(0,l.yg)("hr",null),(0,l.yg)("h2",{id:"dependencies"},"Dependencies"),(0,l.yg)("p",null,"This app definitely wouldn't have been quite so possible without the making use of the following package and components. Full credit and big kudos to their respective authors, who've done an amazing job in building and maintaining them. For a full breakdown of dependency licenses, please see ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/.github/LEGAL.md"},"Legal")),(0,l.yg)("h3",{id:"core"},"Core"),(0,l.yg)("p",null,"At it's core, the application uses ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/vuejs/vue"},(0,l.yg)("strong",{parentName:"a"},"Vue.js")),", as well as it's services with ",(0,l.yg)("a",{parentName:"p",href:"https://vuex.vuejs.org/"},(0,l.yg)("strong",{parentName:"a"},"VueX"))," for state management. Styling is done with ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/sass/sass"},(0,l.yg)("strong",{parentName:"a"},"SCSS")),", JavaScript is currently ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/babel/babel"},(0,l.yg)("strong",{parentName:"a"},"Babel")),", (but I am in the process of converting to ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/Microsoft/TypeScript"},(0,l.yg)("strong",{parentName:"a"},"TypeScript")),"). Linting is done with ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/eslint/eslint"},(0,l.yg)("strong",{parentName:"a"},"ESLint"))," and ",(0,l.yg)("a",{parentName:"p",href:"https://prettier.io/"},(0,l.yg)("strong",{parentName:"a"},"Prettier")),", both following the ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/airbnb/javascript"},(0,l.yg)("strong",{parentName:"a"},"AirBnB Styleguide")),". The config is defined in ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/yaml/yaml"},(0,l.yg)("strong",{parentName:"a"},"YAML")),", with a simple ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/nodejs/node"},(0,l.yg)("strong",{parentName:"a"},"Node.js"))," server to serve up the static app and the optional API endpoints, and container deployment is done with ",(0,l.yg)("a",{parentName:"p",href:"https://www.docker.com/"},(0,l.yg)("strong",{parentName:"a"},"Docker")),"."),(0,l.yg)("h3",{id:"utilities"},"Utilities"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/brix/crypto-js"},(0,l.yg)("inlineCode",{parentName:"a"},"crypto-js"))," - Encryption implementations by @evanvosberg and community ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/axios/axios"},(0,l.yg)("inlineCode",{parentName:"a"},"axios"))," - Promise based HTTP client by @mzabriskie and community ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/ajv-validator/ajv"},(0,l.yg)("inlineCode",{parentName:"a"},"ajv"))," - JSON schema Validator by @epoberezkin and community ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/kazupon/vue-i18n"},(0,l.yg)("inlineCode",{parentName:"a"},"i18n"))," - Internationalization plugin by @kazupon and community ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/frappe/charts"},(0,l.yg)("inlineCode",{parentName:"a"},"frappe-charts"))," - Lightweight charting library by @frappe ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT"))),(0,l.yg)("h3",{id:"frontend-components"},"Frontend Components"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/sagalbot/vue-select"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-select"))," - Dropdown component by @sagalbot ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/euvl/vue-js-modal"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-js-modal"))," - Modal component by @euvl ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/Akryum/v-tooltip"},(0,l.yg)("inlineCode",{parentName:"a"},"v-tooltip"))," - Tooltip component by @Akryum ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/jairoblatt/vue-material-tabs"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-material-tabs"))," - Tab view component by @jairoblatt ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/yansenlei/VJsoneditor"},(0,l.yg)("inlineCode",{parentName:"a"},"VJsoneditor"))," - Interactive JSON editor component by @yansenlei ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT"),(0,l.yg)("ul",{parentName:"li"},(0,l.yg)("li",{parentName:"ul"},"Forked from ",(0,l.yg)("a",{parentName:"li",href:"https://github.com/josdejong/jsoneditor"},(0,l.yg)("inlineCode",{parentName:"a"},"JsonEditor"))," by @josdejong ",(0,l.yg)("inlineCode",{parentName:"li"},"Apache-2.0 License")))),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/shakee93/vue-toasted"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-toasted"))," - Toast notification component by @shakee93 ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT")),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/saintplay/vue-swatches"},(0,l.yg)("inlineCode",{parentName:"a"},"vue-swatches"))," - Color palete picker by @saintplay ",(0,l.yg)("inlineCode",{parentName:"li"},"MIT"))),(0,l.yg)("h3",{id:"backup--sync-server"},"Backup & Sync Server"),(0,l.yg)("p",null,"Although the app is purely frontend, there is an optional cloud sync feature, for off-site backup and restore. This is built as a serverless function on ",(0,l.yg)("a",{parentName:"p",href:"https://workers.cloudflare.com/"},"Cloudflare workers")," using ",(0,l.yg)("a",{parentName:"p",href:"https://developers.cloudflare.com/workers/runtime-apis/kv"},"KV")," and ",(0,l.yg)("a",{parentName:"p",href:"https://developers.cloudflare.com/workers/runtime-apis/web-crypto"},"web crypto")),(0,l.yg)("h3",{id:"external-services"},"External Services"),(0,l.yg)("p",null,"The 1-Click deploy demo uses ",(0,l.yg)("a",{parentName:"p",href:"https://play-with-docker.com/"},"Play-with-Docker Labs"),". Code is hosted on ",(0,l.yg)("a",{parentName:"p",href:"https://github.com"},"GitHub"),", Docker images are hosted on ",(0,l.yg)("a",{parentName:"p",href:"https://hub.docker.com/"},"DockerHub"),", and the demos are hosted on ",(0,l.yg)("a",{parentName:"p",href:"https://www.netlify.com/"},"Netlify"),"."),(0,l.yg)("h3",{id:"actions"},"Actions"),(0,l.yg)("p",null,"This repo makes heavy use of ",(0,l.yg)("a",{parentName:"p",href:"https://github.com/features/actions"},"GitHub actions")," to run automated workflows. The following base actions are totally awesome, and have been extremely useful. Full credit to their respective authors"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/butlerlogic/action-autotag"},(0,l.yg)("inlineCode",{parentName:"a"},"action-autotag"))," by @butlerlogic - Tags new versions when app version changes"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/joeizzard/action-wiki-sync"},(0,l.yg)("inlineCode",{parentName:"a"},"action-wiki-sync"))," by @joeizzard - Copies the markdown docs to the GH wiki"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/bubkoo/contributors-list"},(0,l.yg)("inlineCode",{parentName:"a"},"contributors-list"))," by @bubkoo - Generates contributors SVG"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/akhilmhdh/contributors-readme-action"},(0,l.yg)("inlineCode",{parentName:"a"},"contributors-readme-action"))," by @akhilmhdh - Inserts contributors into credits"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/eter-evans/create-pull-request"},(0,l.yg)("inlineCode",{parentName:"a"},"create-pull-request"))," by @eter-evans - Creates pull request"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/JamesIves/github-pages-deploy-action"},(0,l.yg)("inlineCode",{parentName:"a"},"github-pages-deploy-action"))," by @JamesIves - Deploy app to GH pages"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/apexskier/github-release-commenter"},(0,l.yg)("inlineCode",{parentName:"a"},"github-release-commenter"))," by @apexskier - Updates issues when fix is released"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/JamesIves/github-sponsors-readme-action"},(0,l.yg)("inlineCode",{parentName:"a"},"github-sponsors-readme-action"))," by @JamesIves - Inserts sponsors into credits"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/JasonEtco/is-sponsor-label-action"},(0,l.yg)("inlineCode",{parentName:"a"},"is-sponsor-label-action"))," by @JasonEtco - Label sponsors, for priority support"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/tomsun28/issues-translate-action"},(0,l.yg)("inlineCode",{parentName:"a"},"issues-translate-action"))," by @tomsun28 - Translates non-English issues and comments"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/sobolevn/misspell-fixer-action"},(0,l.yg)("inlineCode",{parentName:"a"},"misspell-fixer-action"))," by @sobolevn - Finds and fixes typos"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/uhyo/please-star-first"},(0,l.yg)("inlineCode",{parentName:"a"},"please-star-first"))," by @uhyo - Closes certain issues by non-stargazers"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/exercism/pr-commenter-action"},(0,l.yg)("inlineCode",{parentName:"a"},"pr-commenter-action"))," by @exercism - Adds info comments to PR based on the files changed"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/snyk/actions/node"},(0,l.yg)("inlineCode",{parentName:"a"},"snyk note"))," by @snyk - Reports vulnerabilities in the code or dependencies"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/alstr/todo-to-issue-action"},(0,l.yg)("inlineCode",{parentName:"a"},"todo-to-issue-action"))," by @alstr - Opens issues from todos in the code"),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("a",{parentName:"li",href:"https://github.com/Simek/yarn-lock-changes"},(0,l.yg)("inlineCode",{parentName:"a"},"yarn-lock-changes"))," by @Simek - Outputs dependency changes in PR")),(0,l.yg)("hr",null),(0,l.yg)("h2",{id:"you"},"You"),(0,l.yg)("p",null,"Would you like to be listed here? Whatever your skill set, Dashy needs people like you to help support future development. Check out the ",(0,l.yg)("a",{parentName:"p",href:"/docs/contributing"},"Contributing Page")," for ways that you can get involved. Huge thank you to everyone who has already contributed! \ud83d\udc96"))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1f5fb0df.24f394c3.js b/assets/js/1f5fb0df.24f394c3.js deleted file mode 100644 index c038321e..00000000 --- a/assets/js/1f5fb0df.24f394c3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[695],{5680:(e,n,a)=>{a.d(n,{xA:()=>c,yg:()=>h});var t=a(6540);function r(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function o(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function i(e){for(var n=1;n=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=t.createContext({}),p=function(e){var n=t.useContext(l),a=n;return e&&(a="function"==typeof e?e(n):i(i({},n),e)),a},c=function(e){var n=p(e.components);return t.createElement(l.Provider,{value:n},e.children)},g="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},d=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),g=p(a),d=r,h=g["".concat(l,".").concat(d)]||g[d]||u[d]||o;return a?t.createElement(h,i(i({ref:n},c),{},{components:a})):t.createElement(h,i({ref:n},c))}));function h(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[g]="string"==typeof e?e:r,i[1]=s;for(var p=2;p{a.r(n),a.d(n,{contentTitle:()=>i,default:()=>g,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var t=a(8168),r=(a(6540),a(5680));const o={},i="App Management",s={unversionedId:"management",id:"management",isDocsHomePage:!1,title:"App Management",description:"The following article is a primer on managing self-hosted apps. It covers everything from keeping the Dashy (or any other app) up-to-date, secure, backed up, to other topics like auto-starting, monitoring, log management, web server configuration and using custom domains.",source:"@site/docs/management.md",sourceDirName:".",slug:"/management",permalink:"/docs/management",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/management.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Configuring",permalink:"/docs/configuring"},next:{title:"Troubleshooting",permalink:"/docs/troubleshooting"}},l=[{value:"Contents",id:"contents",children:[]},{value:"Providing Assets",id:"providing-assets",children:[]},{value:"Running Commands",id:"running-commands",children:[]},{value:"Healthchecks",id:"healthchecks",children:[]},{value:"Logs and Performance",id:"logs-and-performance",children:[{value:"Container Logs",id:"container-logs",children:[]},{value:"Container Performance",id:"container-performance",children:[]},{value:"Management Apps",id:"management-apps",children:[]},{value:"Advanced Logging and Monitoring",id:"advanced-logging-and-monitoring",children:[]}]},{value:"Auto-Starting at System Boot",id:"auto-starting-at-system-boot",children:[]},{value:"Updating",id:"updating",children:[{value:"Updating Docker Container",id:"updating-docker-container",children:[]},{value:"Automatic Docker Updates",id:"automatic-docker-updates",children:[]},{value:"Updating Dashy from Source",id:"updating-dashy-from-source",children:[]}]},{value:"Backing Up",id:"backing-up",children:[{value:"Backing Up Containers",id:"backing-up-containers",children:[]},{value:"Backing Up Volumes",id:"backing-up-volumes",children:[]},{value:"Dashy-Specific Backup",id:"dashy-specific-backup",children:[]}]},{value:"Scheduling",id:"scheduling",children:[]},{value:"SSL Certificates",id:"ssl-certificates",children:[{value:"Auto-SSL",id:"auto-ssl",children:[]},{value:"Getting a Self-Signed SSL Certificate",id:"getting-a-self-signed-ssl-certificate",children:[]},{value:"Passing a Self-Signed Certificate to Dashy",id:"passing-a-self-signed-certificate-to-dashy",children:[]}]},{value:"Authentication",id:"authentication",children:[]},{value:"Managing Containers with Docker Compose",id:"managing-containers-with-docker-compose",children:[]},{value:"Passing in Environmental Variables",id:"passing-in-environmental-variables",children:[]},{value:"Setting Headers",id:"setting-headers",children:[{value:"Example Headers",id:"example-headers",children:[]}]},{value:"Remote Access",id:"remote-access",children:[{value:"WireGuard",id:"wireguard",children:[]},{value:"Reverse SSH Tunnel",id:"reverse-ssh-tunnel",children:[]},{value:"TCP Tunnel",id:"tcp-tunnel",children:[]}]},{value:"Custom Domain",id:"custom-domain",children:[{value:"Using DNS",id:"using-dns",children:[]},{value:"Using NGINX",id:"using-nginx",children:[]}]},{value:"Container Security",id:"container-security",children:[{value:"Keep Docker Up-To-Date",id:"keep-docker-up-to-date",children:[]},{value:"Set Resource Quotas",id:"set-resource-quotas",children:[]},{value:"Don't Run as Root",id:"dont-run-as-root",children:[]},{value:"Specify a User",id:"specify-a-user",children:[]},{value:"Limit capabilities",id:"limit-capabilities",children:[]},{value:"Prevent new Privileges being Added",id:"prevent-new-privileges-being-added",children:[]},{value:"Disable Inter-Container Communication",id:"disable-inter-container-communication",children:[]},{value:"Don't Expose the Docker Daemon Socket",id:"dont-expose-the-docker-daemon-socket",children:[]},{value:"Use Read-Only Volumes",id:"use-read-only-volumes",children:[]},{value:"Set the Logging Level",id:"set-the-logging-level",children:[]},{value:"Verify Image before Pulling",id:"verify-image-before-pulling",children:[]},{value:"Specify the Tag",id:"specify-the-tag",children:[]},{value:"Container Security Scanning",id:"container-security-scanning",children:[]},{value:"Registry Security",id:"registry-security",children:[]},{value:"Security Modules",id:"security-modules",children:[]}]},{value:"Web Server Configuration",id:"web-server-configuration",children:[{value:"NGINX",id:"nginx-1",children:[]},{value:"Apache",id:"apache-1",children:[]},{value:"Caddy",id:"caddy-1",children:[]},{value:"Firebase Hosting",id:"firebase-hosting",children:[]},{value:"cPanel",id:"cpanel",children:[]}]},{value:"Running a Modified Version of the App",id:"running-a-modified-version-of-the-app",children:[]},{value:"Building your Own Container",id:"building-your-own-container",children:[]}],p={toc:l},c="wrapper";function g(e){let{components:n,...a}=e;return(0,r.yg)(c,(0,t.A)({},p,a,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"app-management"},"App Management"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"The following article is a primer on managing self-hosted apps. It covers everything from keeping the Dashy (or any other app) up-to-date, secure, backed up, to other topics like auto-starting, monitoring, log management, web server configuration and using custom domains.")),(0,r.yg)("h2",{id:"contents"},"Contents"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#providing-assets"},"Providing Assets")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#running-commands"},"Running Commands")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#healthchecks"},"Healthchecks")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#logs-and-performance"},"Logs and Performance")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#auto-starting-at-system-boot"},"Auto-Starting at Boot")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#updating"},"Updating")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#backing-up"},"Backing Up")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#scheduling"},"Scheduling")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#ssl-certificates"},"SSL Certificates")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#authentication"},"Authentication")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#managing-containers-with-docker-compose"},"Managing with Compose")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#passing-in-environmental-variables"},"Environmental Variables")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#setting-headers"},"Setting Headers")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#remote-access"},"Remote Access")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#custom-domain"},"Custom Domain")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#container-security"},"Securing Containers")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#web-server-configuration"},"Web Server Configuration")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#running-a-modified-version-of-the-app"},"Running a Modified App")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#building-your-own-container"},"Building your Own Container"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"providing-assets"},"Providing Assets"),(0,r.yg)("p",null,"Although not essential, you will most likely want to provide several assets to your running app."),(0,r.yg)("p",null,"This is easy to do using ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/storage/volumes/"},"Docker Volumes"),", which lets you share a file or directory between your host system, and the container. Volumes are specified in the Docker run command, or Docker compose file, using the ",(0,r.yg)("inlineCode",{parentName:"p"},"--volume")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"-v")," flags. The value of which consists of the path to the file / directory on your host system, followed by the destination path within the container. Fields are separated by a colon (",(0,r.yg)("inlineCode",{parentName:"p"},":"),"), and must be in the correct order. For example: ",(0,r.yg)("inlineCode",{parentName:"p"},"-v ~/alicia/my-local-conf.yml:/app/public/conf.yml")),(0,r.yg)("p",null,"In Dashy, commonly configured resources include:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"./public/conf.yml")," - Your main application config file"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"./public/item-icons")," - A directory containing your own icons. This allows for offline access, and better performance than fetching from a CDN"),(0,r.yg)("li",{parentName:"ul"},"Also within ",(0,r.yg)("inlineCode",{parentName:"li"},"./public")," you'll find standard website assets, including ",(0,r.yg)("inlineCode",{parentName:"li"},"favicon.ico"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"manifest.json"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"robots.txt"),", etc. There's no need to pass these in, but you can do so if you wish"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"/src/styles/user-defined-themes.scss")," - A stylesheet for applying custom CSS to your app. You can also write your own themes here.")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"running-commands"},"Running Commands"),(0,r.yg)("p",null,"If you're running an app in Docker, then commands will need to be passed to the container to be executed. This can be done by preceding each command with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it [container-id]"),", where container ID can be found by running ",(0,r.yg)("inlineCode",{parentName:"p"},"docker ps"),". For example ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it 26c156c467b4 yarn build"),". You can also enter the container, with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it [container-id] /bin/ash"),", and navigate around it with normal Linux commands."),(0,r.yg)("p",null,"Dashy has several commands that can be used for various tasks, you can find a list of these either in the ",(0,r.yg)("a",{parentName:"p",href:"/docs/developing#project-commands"},"Developing Docs"),", or by looking at the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/package.json#L5"},(0,r.yg)("inlineCode",{parentName:"a"},"package.json")),". These can be used by running ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn [command-name]"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"healthchecks"},"Healthchecks"),(0,r.yg)("p",null,"Healthchecks are configured to periodically check that Dashy is up and running correctly on the specified port. By default, the health script is called every 5 minutes, but this can be modified with the ",(0,r.yg)("inlineCode",{parentName:"p"},"--health-interval")," option. You can check the current container health with: ",(0,r.yg)("inlineCode",{parentName:"p"},'docker inspect --format "{{json .State.Health }}" [container-id]'),", and a summary of health status will show up under ",(0,r.yg)("inlineCode",{parentName:"p"},"docker ps"),". You can also manually request the current application status by running ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it [container-id] yarn health-check"),". You can disable healthchecks altogether by adding the ",(0,r.yg)("inlineCode",{parentName:"p"},"--no-healthcheck")," flag to your Docker run command."),(0,r.yg)("p",null,"To restart unhealthy containers automatically, check out ",(0,r.yg)("a",{parentName:"p",href:"https://hub.docker.com/r/willfarrell/autoheal/"},"Autoheal"),". This image watches for unhealthy containers, and automatically triggers a restart. (This is a stand in for Docker's ",(0,r.yg)("inlineCode",{parentName:"p"},"--exit-on-unhealthy")," that was proposed, but ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/moby/moby/pull/22719"},"not merged"),"). There's also ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/qdm12/deunhealth"},"Deunhealth"),", which is super light-weight, and doesn't require network access."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n --name autoheal \\\n --restart=always \\\n -e AUTOHEAL_CONTAINER_LABEL=all \\\n -v /var/run/docker.sock:/var/run/docker.sock \\\n willfarrell/autoheal\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"logs-and-performance"},"Logs and Performance"),(0,r.yg)("h3",{id:"container-logs"},"Container Logs"),(0,r.yg)("p",null,"You can view logs for a given Docker container with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker logs [container-id]"),", add the ",(0,r.yg)("inlineCode",{parentName:"p"},"--follow")," flag to stream the logs. For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/containers/logging/"},"Logging Documentation"),". There's also ",(0,r.yg)("a",{parentName:"p",href:"https://dozzle.dev/"},"Dozzle"),", a useful tool, that provides a web interface where you can stream and query logs from all your running containers from a single web app."),(0,r.yg)("h3",{id:"container-performance"},"Container Performance"),(0,r.yg)("p",null,"You can check the resource usage for your running Docker containers with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker stats")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"docker stats [container-id]"),". For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/stats/"},"Stats Documentation"),". There's also ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/google/cadvisor"},"cAdvisor"),", a useful web app for viewing and analyzing resource usage and performance of all your running containers."),(0,r.yg)("h3",{id:"management-apps"},"Management Apps"),(0,r.yg)("p",null,"You can also view logs, resource usage and other info as well as manage your entire Docker workflow in third-party Docker management apps. For example ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/portainer/portainer"},"Portainer")," an all-in-one open source management web UI for Docker and Kubernetes, or ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/jesseduffield/lazydocker"},"LazyDocker")," a terminal UI for Docker container management and monitoring."),(0,r.yg)("h3",{id:"advanced-logging-and-monitoring"},"Advanced Logging and Monitoring"),(0,r.yg)("p",null,"Docker supports using ",(0,r.yg)("a",{parentName:"p",href:"https://prometheus.io/"},"Prometheus")," to collect logs, which can then be visualized using a platform like ",(0,r.yg)("a",{parentName:"p",href:"https://grafana.com/"},"Grafana"),". For more info, see ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/daemon/prometheus/"},"this guide"),". If you need to route your logs to a remote syslog, then consider using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/gliderlabs/logspout"},"logspout"),". For enterprise-grade instances, there are managed services, that make monitoring container logs and metrics very easy, such as ",(0,r.yg)("a",{parentName:"p",href:"https://sematext.com/blog/docker-container-monitoring-with-sematext/"},"Sematext")," with ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/sematext/logagent-js"},"Logagent"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"auto-starting-at-system-boot"},"Auto-Starting at System Boot"),(0,r.yg)("p",null,"You can use Docker's ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/run/#restart-policies---restart"},"restart policies")," to instruct the container to start after a system reboot, or restart after a crash. Just add the ",(0,r.yg)("inlineCode",{parentName:"p"},"--restart=always")," flag to your Docker compose script or Docker run command. For more information, see the docs on ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/containers/start-containers-automatically/"},"Starting Containers Automatically"),"."),(0,r.yg)("p",null,"For Podman, you can use ",(0,r.yg)("inlineCode",{parentName:"p"},"systemd")," to create a service that launches your container, ",(0,r.yg)("a",{parentName:"p",href:"https://podman.io/blogs/2018/09/13/systemd.html"},"the docs")," explains things further. A similar approach can be used with Docker, if you need to start containers after a reboot, but before any user interaction."),(0,r.yg)("p",null,"To restart the container after something within it has crashed, consider using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/willfarrell/docker-autoheal"},(0,r.yg)("inlineCode",{parentName:"a"},"docker-autoheal"))," by @willfarrell, a service that monitors and restarts unhealthy containers. For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"#healthchecks"},"Healthchecks")," section above."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"updating"},"Updating"),(0,r.yg)("p",null,"Dashy is under active development, so to take advantage of the latest features, you may need to update your instance every now and again."),(0,r.yg)("h3",{id:"updating-docker-container"},"Updating Docker Container"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Pull latest image: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker pull lissy93/dashy:latest")),(0,r.yg)("li",{parentName:"ol"},"Kill off existing container",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Find container ID: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker ps")),(0,r.yg)("li",{parentName:"ul"},"Stop container: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker stop [container_id]")),(0,r.yg)("li",{parentName:"ul"},"Remove container: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker rm [container_id]")))),(0,r.yg)("li",{parentName:"ol"},"Spin up new container: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker run [params] lissy93/dashy"))),(0,r.yg)("h3",{id:"automatic-docker-updates"},"Automatic Docker Updates"),(0,r.yg)("p",null,"You can automate the above process using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/containrrr/watchtower"},"Watchtower"),".\nWatchtower will watch for new versions of a given image on Docker Hub, pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially."),(0,r.yg)("p",null,"To get started, spin up the watchtower container:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n --name watchtower \\\n -v /var/run/docker.sock:/var/run/docker.sock \\\n containrrr/watchtower\n")),(0,r.yg)("p",null,"For more information, see the ",(0,r.yg)("a",{parentName:"p",href:"https://containrrr.dev/watchtower/"},"Watchtower Docs")),(0,r.yg)("h3",{id:"updating-dashy-from-source"},"Updating Dashy from Source"),(0,r.yg)("p",null,"Stop your current instance of Dashy, then navigate into the source directory. Pull down the latest code, with ",(0,r.yg)("inlineCode",{parentName:"p"},"git pull origin master"),", then update dependencies with ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn"),", rebuild with ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn build"),", and start the server again with ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn start"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"backing-up"},"Backing Up"),(0,r.yg)("h3",{id:"backing-up-containers"},"Backing Up Containers"),(0,r.yg)("p",null,"You can make a backup of any running container really easily, using ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/commit/"},(0,r.yg)("inlineCode",{parentName:"a"},"docker commit"))," and save it with ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/export/"},(0,r.yg)("inlineCode",{parentName:"a"},"docker export")),", to do so:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"First find the container ID, you can do this with ",(0,r.yg)("inlineCode",{parentName:"li"},"docker container ls")),(0,r.yg)("li",{parentName:"ul"},"Now to create the snapshot, just run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker commit -p [container-id] my-backup")),(0,r.yg)("li",{parentName:"ul"},"Finally, to save the backup locally, run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker save -o ~/dashy-backup.tar my-backup")),(0,r.yg)("li",{parentName:"ul"},"If you want to push this to a container registry, run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker push my-backup:latest"))),(0,r.yg)("p",null,"Note that this will not include any data in docker volumes, and the process here is a bit different. Since these files exist on your host system, if you have an existing backup solution implemented, you can incorporate and volume files within that system."),(0,r.yg)("h3",{id:"backing-up-volumes"},"Backing Up Volumes"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://github.com/offen/docker-volume-backup"},"offen/docker-volume-backup")," is a useful tool for periodic Docker volume backups, to any S3-compatible storage provider. It's run as a light-weight Docker container, and is easy to setup, and also supports GPG-encryption, email notification, and routing away older backups."),(0,r.yg)("p",null,"To get started, create a docker-compose similar to the example below, and then start the container. For more info, check out their ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/offen/docker-volume-backup"},"documentation"),", which is very clear."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"version: '3'\nservices:\n backup:\n image: offen/docker-volume-backup:latest\n environment:\n BACKUP_CRON_EXPRESSION: \"0 * * * *\"\n BACKUP_PRUNING_PREFIX: backup-\n BACKUP_RETENTION_DAYS: 7\n AWS_BUCKET_NAME: backup-bucket\n AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE\n AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n volumes:\n - data:/backup/my-app-backup:ro\n - /var/run/docker.sock:/var/run/docker.sock:ro\nvolumes:\n data:\n")),(0,r.yg)("p",null,"It's worth noting that this process can also be done manually, using the following commands:"),(0,r.yg)("p",null,"Backup:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run --rm -v some_volume:/volume -v /tmp:/backup alpine tar -cjf /backup/some_archive.tar.bz2 -C /volume ./\n")),(0,r.yg)("p",null,"Restore:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'docker run --rm -v some_volume:/volume -v /tmp:/backup alpine sh -c "rm -rf /volume/* /volume/..?* /volume/.[!.]* ; tar -C /volume/ -xjf /backup/some_archive.tar.bz2"\n')),(0,r.yg)("h3",{id:"dashy-specific-backup"},"Dashy-Specific Backup"),(0,r.yg)("p",null,"Since Dashy is open source, and freely available, providing you're configuration data is passed in as volumes, there shouldn't be any need to backup the main container. Your main config file, and any assets you're using should be kept backed up, preferably in at least two places, and you should ensure that you can easily restore from backup, if needed."),(0,r.yg)("p",null,"Dashy also has a built-in cloud backup feature, which is free for personal users, and will let you make and restore fully encrypted backups of your config directly through the UI. To learn more, see the ",(0,r.yg)("a",{parentName:"p",href:"/docs/backup-restore"},"Cloud Backup Docs")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"scheduling"},"Scheduling"),(0,r.yg)("p",null,"If you need to periodically schedule the running of a given command on Dashy (or any other container), then a useful tool for doing so it ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/mcuadros/ofelia"},"ofelia"),". This runs as a Docker container and is really useful for things like backups, logging, updating, notifications, etc. Crons are specified using Go's crontab format, and a useful tool for visualizing this is ",(0,r.yg)("a",{parentName:"p",href:"https://crontab.guru/"},"crontab.guru"),". This can also be done natively with Alpine: ",(0,r.yg)("inlineCode",{parentName:"p"},"docker run -it alpine ls /etc/periodic"),".\nI recommend combining this with ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/healthchecks/healthchecks"},"healthchecks")," for easy monitoring of jobs, and failure notifications."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"ssl-certificates"},"SSL Certificates"),(0,r.yg)("p",null,"Enabling HTTPS with an SSL certificate is recommended, especially if you are hosting Dashy anywhere other than your home. This will ensure that all traffic is encrypted in transit."),(0,r.yg)("h3",{id:"auto-ssl"},"Auto-SSL"),(0,r.yg)("p",null,"If you are using ",(0,r.yg)("a",{parentName:"p",href:"https://nginxproxymanager.com/"},"NGINX Proxy Manager"),', then SSL is supported out of the box. Once you\'ve added your proxy host and web address, then set the scheme to HTTPS, then under the SSL Tab select "Request a new SSL certificate" and follow the on-screen instructions.'),(0,r.yg)("p",null,"If you're hosting Dashy behind Cloudflare, then they offer ",(0,r.yg)("a",{parentName:"p",href:"https://www.cloudflare.com/en-gb/learning/ssl/what-is-an-ssl-certificate/"},"free and easy SSL"),"- all you need to do is enable it under the SSL/TLS tab. Or if you are using shared hosting, you may find ",(0,r.yg)("a",{parentName:"p",href:"https://www.sitepoint.com/a-guide-to-setting-up-lets-encrypt-ssl-on-shared-hosting/"},"this tutorial")," helpful."),(0,r.yg)("h3",{id:"getting-a-self-signed-ssl-certificate"},"Getting a Self-Signed SSL Certificate"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://letsencrypt.org/docs/"},"Let's Encrypt")," is a global Certificate Authority, providing free SSL/TLS Domain Validation certificates in order to enable secure HTTPS access to your website. They have good browser/ OS ",(0,r.yg)("a",{parentName:"p",href:"https://letsencrypt.org/docs/certificate-compatibility/"},"compatibility")," with their ISRG X1 and DST CA X3 root certificates, support ",(0,r.yg)("a",{parentName:"p",href:"https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578"},"Wildcard issuance")," done via ACMEv2 using the DNS-01 and have ",(0,r.yg)("a",{parentName:"p",href:"https://letsencrypt.org/2020/02/19/multi-perspective-validation.html"},"Multi-Perspective Validation"),". Let's Encrypt provide ",(0,r.yg)("a",{parentName:"p",href:"https://certbot.eff.org/"},"CertBot")," an easy app for generating and setting up an SSL certificate."),(0,r.yg)("p",null,"This process can be automated, using something like the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Valian/docker-nginx-auto-ssl"},"Docker-NGINX-Auto-SSL Container")," to generate and renew certificates when needed."),(0,r.yg)("p",null,"If you're not so comfortable on the command line, then you can use a tool like ",(0,r.yg)("a",{parentName:"p",href:"https://www.sslforfree.com/"},"SSL For Free")," or ",(0,r.yg)("a",{parentName:"p",href:"https://zerossl.com/"},"ZeroSSL")," to generate your cert. They also provide step-by-step setup instructions for most platforms."),(0,r.yg)("h3",{id:"passing-a-self-signed-certificate-to-dashy"},"Passing a Self-Signed Certificate to Dashy"),(0,r.yg)("p",null,"Once you've generated your SSL cert, you'll need to pass it to Dashy. This can be done by specifying the paths to your public and private keys using the ",(0,r.yg)("inlineCode",{parentName:"p"},"SSL_PRIV_KEY_PATH")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"SSL_PUB_KEY_PATH")," environmental variables. Or if you're using Docker, then just pass public + private SSL keys in under ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/ssl/certs/dashy-pub.pem")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/ssl/certs/dashy-priv.key")," respectively, e.g:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n -p 8080:80 \\\n -v ~/my-private-key.key:/etc/ssl/certs/dashy-priv.key:ro \\\n -v ~/my-public-key.pem:/etc/ssl/certs/dashy-pub.pem:ro \\\n lissy93/dashy:latest\n")),(0,r.yg)("p",null,"By default the SSL port is ",(0,r.yg)("inlineCode",{parentName:"p"},"443")," within a Docker container, or ",(0,r.yg)("inlineCode",{parentName:"p"},"4001")," if running on bare metal, but you can override this with the ",(0,r.yg)("inlineCode",{parentName:"p"},"SSL_PORT")," environmental variable."),(0,r.yg)("p",null,"Once everything is setup, you can verify your site is secured using a tool like ",(0,r.yg)("a",{parentName:"p",href:"https://www.sslchecker.com/sslchecker"},"SSL Checker"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"authentication"},"Authentication"),(0,r.yg)("p",null,"Dashy natively supports secure authentication using KeyCloak. There is also a Simple Auth feature that doesn't require any additional setup. Usage instructions for both, as well as alternative auth methods, has now moved to the ",(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"/docs/authentication"},"Authentication Docs"))," page."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"managing-containers-with-docker-compose"},"Managing Containers with Docker Compose"),(0,r.yg)("p",null,"When you have a lot of containers, it quickly becomes hard to manage with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker run")," commands. The solution to this is ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/compose/"},"docker compose"),", a handy tool for defining all a containers run settings in a single YAML file, and then spinning up that container with a single short command - ",(0,r.yg)("inlineCode",{parentName:"p"},"docker compose up"),". A good example of which can be seen in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/abhilesh/self-hosted_docker_setups"},"@abhilesh's docker compose collection"),"."),(0,r.yg)("p",null,"You can use Dashy's default ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docker-compose.yml"},(0,r.yg)("inlineCode",{parentName:"a"},"docker-compose.yml"))," file as a template, and modify it according to your needs."),(0,r.yg)("p",null,"An example Docker compose, using the default base image from DockerHub, might look something like this:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"---\nversion: \"3.8\"\nservices:\n dashy:\n container_name: Dashy\n image: lissy93/dashy\n volumes:\n - /root/my-config.yml:/app/public/conf.yml\n ports:\n - 4000:80\n environment:\n - BASE_URL=/my-dashboard\n restart: unless-stopped\n healthcheck:\n test: ['CMD', 'node', '/app/services/healthcheck']\n interval: 1m30s\n timeout: 10s\n retries: 3\n start_period: 40s\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"passing-in-environmental-variables"},"Passing in Environmental Variables"),(0,r.yg)("p",null,"With Docker, you can define environmental variables under the ",(0,r.yg)("inlineCode",{parentName:"p"},"environment")," section of your Docker compose file. Environmental variables are used to configure high-level settings, usually before the config file has been read. For a list of all supported env vars in Dashy, see ",(0,r.yg)("a",{parentName:"p",href:"/docs/developing#environmental-variables"},"the developing docs"),", or the default ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/.env"},(0,r.yg)("inlineCode",{parentName:"a"},".env"))," file."),(0,r.yg)("p",null,"A common use case, is to run Dashy under a sub-page, instead of at the root of a URL (e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"https://my-homelab.local/dashy")," instead of ",(0,r.yg)("inlineCode",{parentName:"p"},"https://dashy.my-homelab.local"),"). In this use-case, you'd specify the ",(0,r.yg)("inlineCode",{parentName:"p"},"BASE_URL")," variable in your compose file."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"environment:\n - BASE_URL=/dashy\n")),(0,r.yg)("p",null,"You can also do the same thing with the docker run command, using the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file"},(0,r.yg)("inlineCode",{parentName:"a"},"--env"))," flag.\nIf you've got many environmental variables, you might find it useful to put them in a ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/compose/env-file/"},(0,r.yg)("inlineCode",{parentName:"a"},".env")," file"),". Similarly, for Docker run you can use ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file"},(0,r.yg)("inlineCode",{parentName:"a"},"--env-file"))," if you'd like to pass in a file containing all your environmental variables."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"setting-headers"},"Setting Headers"),(0,r.yg)("p",null,"Any external requests made to a different origin (app/ service under a different domain) will be blocked if the correct headers are not specified. This is known as ",(0,r.yg)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"Cross-Origin Resource Sharing")," (CORS) and is a security feature built into modern browsers."),(0,r.yg)("p",null,"If you see a CORS error in your console, this can be easily fixed by setting the correct headers. This is not a bug with Dashy, so please don't raise it as a bug!"),(0,r.yg)("h3",{id:"example-headers"},"Example Headers"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#caddy"},"Caddy")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nginx"},"NGINX")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#traefik"},"Tr\xe6f\u026ak")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#haproxy"},"HAProxy")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#apache"},"Apache"))),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"The following section briefly outlines how you can set headers for common web proxies/ servers. More info can be found in the documentation for the proxy that you are using, or in the ",(0,r.yg)("a",{parentName:"em",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"MDN Docs"),".")),(0,r.yg)("p",null,"These examples are using:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Access-Control-Allow-Origin")," header, but depending on what type of content you are enabling, this will vary. For example, to allow a site to be loaded in an iframe (for the modal or workspace views) you would use ",(0,r.yg)("inlineCode",{parentName:"li"},"X-Frame-Options"),"."),(0,r.yg)("li",{parentName:"ul"},"The domain root (",(0,r.yg)("inlineCode",{parentName:"li"},"/"),"), if your're hosting from a sub-page, replace that with your path."),(0,r.yg)("li",{parentName:"ul"},"A wildcard (",(0,r.yg)("inlineCode",{parentName:"li"},"*"),"), which would allow access from traffic on any domain, this is discouraged, and you should replace it with the URL where you are hosting Dashy. Note that for requests that transport sensitive info, like credentials (e.g. Keycloak login), the wildcard is ",(0,r.yg)("a",{parentName:"li",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#requests_with_credentials"},"disallowed all together")," and will be blocked.")),(0,r.yg)("h4",{id:"caddy"},"Caddy"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://caddyserver.com/docs/caddyfile/directives/header"},"Caddy ",(0,r.yg)("inlineCode",{parentName:"a"},"header")," docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"headers / {\n Access-Control-Allow-Origin *\n}\n")),(0,r.yg)("h4",{id:"nginx"},"NGINX"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://nginx.org/en/docs/http/ngx_http_headers_module.html"},"NGINX ",(0,r.yg)("inlineCode",{parentName:"a"},"ngx_http_headers_module")," docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"location / {\n add_header Access-Control-Allow-Origin *;\n}\n")),(0,r.yg)("p",null,"Note this can also be done through the UI, using NGINX Proxy Manager."),(0,r.yg)("h4",{id:"traefik"},"Traefik"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://doc.traefik.io/traefik/middlewares/http/headers/#cors-headers"},"Tr\xe6f\u026ak CORS headers docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},'labels:\n - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"\n - "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org"\n - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"\n - "traefik.http.middlewares.testheader.headers.addvaryheader=true"\n')),(0,r.yg)("h4",{id:"haproxy"},"HAProxy"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://www.haproxy.com/documentation/hapee/latest/traffic-routing/rewrites/rewrite-responses/"},"HAProxy Rewrite Response Docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"/\n http-response add-header Access-Control-Allow-Origin *\n")),(0,r.yg)("h4",{id:"apache"},"Apache"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://httpd.apache.org/docs/current/mod/mod_headers.html"},"Apache ",(0,r.yg)("inlineCode",{parentName:"a"},"mode_headers")," docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},'Header always set Access-Control-Allow-Origin "*"\n')),(0,r.yg)("h4",{id:"squid"},"Squid"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"http://www2.gr.squid-cache.org/Doc/config/request_header_access/"},"Squid ",(0,r.yg)("inlineCode",{parentName:"a"},"request_header_access")," docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"request_header_access Authorization allow all\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"remote-access"},"Remote Access"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#wireguard"},"WireGuard")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#reverse-ssh-tunnel"},"Reverse SSH Tunnel")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#tcp-tunnel"},"TCP Tunnel"))),(0,r.yg)("h3",{id:"wireguard"},"WireGuard"),(0,r.yg)("p",null,"Using a VPN is one of the easiest ways to provide secure, full access to your local network from remote locations. ",(0,r.yg)("a",{parentName:"p",href:"https://www.wireguard.com/"},"WireGuard")," is a reasonably new open source VPN protocol, that was designed with ease of use, performance and security in mind. Unlike OpenVPN, it doesn't need to recreate the tunnel whenever connection is dropped, and it's also much easier to setup, using shared keys instead."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Install Wireguard")," - See the ",(0,r.yg)("a",{parentName:"li",href:"https://www.wireguard.com/install/"},"Install Docs")," for download links + instructions",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"On Debian-based systems, it's ",(0,r.yg)("inlineCode",{parentName:"li"},"sudo apt install wireguard")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Generate a Private Key")," - Run ",(0,r.yg)("inlineCode",{parentName:"li"},"wg genkey")," on the Wireguard server, and copy it to somewhere safe for later"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Create Server Config")," - Open or create a file at ",(0,r.yg)("inlineCode",{parentName:"li"},"/etc/wireguard/wg0.conf")," and under ",(0,r.yg)("inlineCode",{parentName:"li"},"[Interface]")," add the following (see example below):",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Address")," - as a subnet of all desired IPs"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"PrivateKey")," - that you just generated"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"ListenPort")," - Default is ",(0,r.yg)("inlineCode",{parentName:"li"},"51820"),", but can be anything"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Get Client App")," - Download the ",(0,r.yg)("a",{parentName:"li",href:"https://www.wireguard.com/install/"},"WG client app")," for your platform (Linux, Windows, MacOS, Android or iOS are all supported)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Create new Client Tunnel")," - On your client app, there should be an option to create a new tunnel, when doing so a client private key will be generated (but if not, use the ",(0,r.yg)("inlineCode",{parentName:"li"},"wg genkey")," command again), and keep it somewhere safe. A public key will also be generated, and this will go in our saver config"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Add Clients to Server Config")," - Head back to your ",(0,r.yg)("inlineCode",{parentName:"li"},"wg0.conf")," file on the server, create a ",(0,r.yg)("inlineCode",{parentName:"li"},"[Peer]")," section, and populate the following info",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"AllowedIPs")," - List of IP address inside the subnet, the client should have access to"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"PublicKey")," - The public key for the client you just generated"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Start the Server")," - You can now start the WG server, using: ",(0,r.yg)("inlineCode",{parentName:"li"},"wg-quick up wg0")," on your server"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Finish Client Setup")," - Head back to your client device, and edit the config file, leave the private key as is, and add the following fields:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"PublicKey")," - The public key of the server"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Address")," - This should match the ",(0,r.yg)("inlineCode",{parentName:"li"},"AllowedIPs")," section on the servers config file"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"DNS")," - The DNS server that'll be used when accessing the network through the VPN"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Endpoint")," - The hostname or IP + Port where your WG server is running (you may need to forward this in your firewall's settings)"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Done")," - Your clients should now be able to connect to your WG server :) Depending on your networks firewall rules, you may need to port forward the address of your WG server")),(0,r.yg)("h4",{id:"example-server-config"},(0,r.yg)("strong",{parentName:"h4"},"Example Server Config")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-ini"},"# Server file\n[Interface]\n# Which networks does my interface belong to? Notice: /24 and /64\nAddress = 10.5.0.1/24, 2001:470:xxxx:xxxx::1/64\nPrivateKey = xxx\nListenPort = 51820\n\n# Peer 1\n[Peer]\nPublicKey = xxx\n# Which source IPs can I expect from that peer? Notice: /32 and /128\nAllowedIps = 10.5.0.35/32, 2001:470:xxxx:xxxx::746f:786f/128\n\n# Peer 2\n[Peer]\nPublicKey = xxx\n# Which source IPs can I expect from that peer? This one has a LAN which can\n# access hosts/jails without NAT.\n# Peer 2 has a single IP address inside the VPN: it's 10.5.0.25/32\nAllowedIps = 10.5.0.25/32,10.21.10.0/24,10.21.20.0/24,10.21.30.0/24,10.31.0.0/24,2001:470:xxxx:xxxx::ca:571e/128\n")),(0,r.yg)("h4",{id:"example-client-config"},(0,r.yg)("strong",{parentName:"h4"},"Example Client Config")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-ini"},"[Interface]\n# Which networks does my interface belong to? Notice: /24 and /64\nAddress = 10.5.0.35/24, 2001:470:xxxx:xxxx::746f:786f/64\nPrivateKey = xxx\n\n# Server\n[Peer]\nPublicKey = xxx\n# I want to route everything through the server, both IPv4 and IPv6. All IPs are\n# thus available through the Server, and I can expect packets from any IP to\n# come from that peer.\nAllowedIPs = 0.0.0.0/0, ::0/0\n# Where is the server on the internet? This is a public address. The port\n# (:51820) is the same as ListenPort in the [Interface] of the Server file above\nEndpoint = 1.2.3.4:51820\n# Usually, clients are behind NAT. to keep the connection running, keep alive.\nPersistentKeepalive = 15\n")),(0,r.yg)("p",null,"A useful tool for getting WG setup is ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/trailofbits/algo"},"Algo"),". It includes scripts and docs which cover almost all devices, platforms and clients, and has best practices implemented, and security features enabled. All of this is better explained in ",(0,r.yg)("a",{parentName:"p",href:"https://blog.trailofbits.com/2016/12/12/meet-algo-the-vpn-that-works/"},"this blog post"),"."),(0,r.yg)("h3",{id:"reverse-ssh-tunnel"},"Reverse SSH Tunnel"),(0,r.yg)("p",null,"SSH (or ",(0,r.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Secure_Shell"},"Secure Shell"),") is a secure tunnel that allows you to connect to a remote host. Unlike the VPN methods, an SSH connection does not require an intermediary, and will not be affected by your IP changing. However it only allows you to access a single service at a time. SSH was really designed for terminal access, but because of the latter mentioned benefits it's useful to setup, as a fallback option."),(0,r.yg)("p",null,"Directly SSH'ing into your home, would require you to open a port (usually 22), which would be terrible for security, and is not recommended. However a reverse SSH connection is initiated from inside your network. Once the connection is established, the port is redirected, allowing you to use the established connection to SSH into your home network."),(0,r.yg)("p",null,"The issue you've probably spotted, is that most public, corporate, and institutional networks will block SSH connections. To overcome this, you'd have to establish a server outside of your homelab that your homelab's device could SSH into to establish the reverse SSH connection. You can then connect to that remote server (the ",(0,r.yg)("em",{parentName:"p"},"mothership"),"), which in turn connects to your home network."),(0,r.yg)("p",null,"Now all of this is starting to sound like quite a lot of work, but this is where services like ",(0,r.yg)("a",{parentName:"p",href:"https://remote.it/"},"remot3.it")," come in. They maintain the intermediary mothership server, and create the tunnel service for you. It's free for personal use, secure and easy. There are several similar services, such as ",(0,r.yg)("a",{parentName:"p",href:"https://remoteiot.com/"},"RemoteIoT"),", or you could create your own on a cloud VPS (see ",(0,r.yg)("a",{parentName:"p",href:"https://gist.github.com/nileshtrivedi/4c615e8d3c1bf053b0d31176b9e69e42"},"this tutorial")," for more info on that)."),(0,r.yg)("p",null,"Before getting started, you'll need to head over to ",(0,r.yg)("a",{parentName:"p",href:"https://app.remote.it/auth/#/sign-up"},"Remote.it")," and create an account."),(0,r.yg)("p",null,"Then setup your local device:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"If you haven't already done so, you'll need to enable and configure SSH.",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"This is out-of-scope of this article, but I've explained it in detail in ",(0,r.yg)("a",{parentName:"li",href:"https://notes.aliciasykes.com/22798/my-server-setup#configure-ssh"},"this post"),"."))),(0,r.yg)("li",{parentName:"ol"},"Download the Remote.it install script from their ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/remoteit/installer"},"GitHub"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"curl -LkO https://raw.githubusercontent.com/remoteit/installer/master/scripts/auto-install.sh")))),(0,r.yg)("li",{parentName:"ol"},"Make it executable, with ",(0,r.yg)("inlineCode",{parentName:"li"},"chmod +x ./auto-install.sh"),", and then run it with ",(0,r.yg)("inlineCode",{parentName:"li"},"sudo ./auto-install.sh")),(0,r.yg)("li",{parentName:"ol"},"Finally, configure your device, by running ",(0,r.yg)("inlineCode",{parentName:"li"},"sudo connectd_installer")," and following the on-screen instructions")),(0,r.yg)("p",null,"And when you're ready to connect to it:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Login to ",(0,r.yg)("a",{parentName:"li",href:"https://app.remote.it/"},"app.remote.it"),", and select the name of your device"),(0,r.yg)("li",{parentName:"ol"},"You should see a list of running services, click SSH"),(0,r.yg)("li",{parentName:"ol"},"You'll then be presented with some SSH credentials that you can now use to securely connect to your home, via the Remote.it servers")),(0,r.yg)("p",null,"Done :)"),(0,r.yg)("h3",{id:"tcp-tunnel"},"TCP Tunnel"),(0,r.yg)("p",null,"If you're running Dashy on your local network, behind a firewall, but need to temporarily share it with someone external, this can be achieved quickly and securely using ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/"},"Ngrok"),". It's basically a super slick, encrypted TCP tunnel that provides an internet-accessible address that anyone use to access your local service, from anywhere."),(0,r.yg)("p",null,"To get started, ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/download"},"Download")," and install Ngrok for your system, then just run ",(0,r.yg)("inlineCode",{parentName:"p"},"ngrok http [port]")," (replace the port with the http port where Dashy is running, e.g. 8080). When ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs#http-local-https"},"using https"),", specify the full local url/ ip including the protocol."),(0,r.yg)("p",null,"Some Ngrok features require you to be authenticated, you can ",(0,r.yg)("a",{parentName:"p",href:"https://dashboard.ngrok.com/signup"},"create a free account")," and generate a token in ",(0,r.yg)("a",{parentName:"p",href:"https://dashboard.ngrok.com/auth/your-authtoken"},"your dashboard"),", then run ",(0,r.yg)("inlineCode",{parentName:"p"},"ngrok authtoken [token]"),"."),(0,r.yg)("p",null,"It's recommended to use authentication for any publicly accessible service. Dashy has an ",(0,r.yg)("a",{parentName:"p",href:"/docs/authentication"},"Auth")," feature built in, but an even easier method it to use the ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs#http-auth"},(0,r.yg)("inlineCode",{parentName:"a"},"-auth"))," switch. E.g. ",(0,r.yg)("inlineCode",{parentName:"p"},'ngrok http -auth="username:password123" 8080')),(0,r.yg)("p",null,"By default, your web app is assigned a randomly generated ngrok domain, but you can also use your own custom domain. Under the ",(0,r.yg)("a",{parentName:"p",href:"https://dashboard.ngrok.com/endpoints/domains"},"Domains Tab")," of your Ngrok dashboard, add your domain, and follow the CNAME instructions. You can now use your domain, with the ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs#http-custom-domains"},(0,r.yg)("inlineCode",{parentName:"a"},"-hostname"))," switch, e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"ngrok http -region=us -hostname=dashy.example.com 8080"),". If you don't have your own domain name, you can instead use a custom sub-domain (e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"alicia-dashy.ngrok.io"),"), using the ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs#custom-subdomain-names"},(0,r.yg)("inlineCode",{parentName:"a"},"-subdomain"))," switch."),(0,r.yg)("p",null,"To integrate this into your docker-compose, take a look at the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/gtriggiano/ngrok-tunnel"},"gtriggiano/ngrok-tunnel")," container."),(0,r.yg)("p",null,"There's so much more you can do with Ngrok, such as exposing a directory as a file browser, using websockets, relaying requests, rewriting headers, inspecting traffic, TLS and TCP tunnels and lots more. All or which is explained in ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs"},"the Documentation"),"."),(0,r.yg)("p",null,"It's worth noting that Ngrok isn't the only option here, other options include: ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/fatedier/frp"},"FRP"),", ",(0,r.yg)("a",{parentName:"p",href:"https://inlets.dev"},"Inlets"),", ",(0,r.yg)("a",{parentName:"p",href:"https://localtunnel.me/"},"Local Tunnel"),", ",(0,r.yg)("a",{parentName:"p",href:"https://tailscale.com/"},"TailScale"),", etc. Check out ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/anderspitman/awesome-tunneling"},"Awesome Tunneling")," for a list of alternatives."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"custom-domain"},"Custom Domain"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#using-nginx"},"Using DNS")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#using-dns"},"Using NGINX"))),(0,r.yg)("h3",{id:"using-dns"},"Using DNS"),(0,r.yg)("p",null,"For locally running services, a domain can be set up directly in the DNS records. This method is really quick and easy, and doesn't require you to purchase an actual domain. Just update your networks DNS resolver, to point your desired URL to the local IP where Dashy (or any other app) is running. For example, a line in your hosts file might look something like: ",(0,r.yg)("inlineCode",{parentName:"p"},"192.168.0.2 dashy.homelab.local"),"."),(0,r.yg)("p",null,"If you're using Pi-Hole, a similar thing can be done in the ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/dnsmasq.d/03-custom-dns.conf")," file, add a line like: ",(0,r.yg)("inlineCode",{parentName:"p"},"address=/dashy.example.com/192.168.2.0")," for each of your services."),(0,r.yg)("p",null,"If you're running OPNSense/ PfSense, then this can be done through the UI with Unbound, it's explained nicely in ",(0,r.yg)("a",{parentName:"p",href:"https://homenetworkguy.com/how-to/use-custom-domain-name-in-internal-network/"},"this article"),", by Dustin Casto."),(0,r.yg)("h3",{id:"using-nginx"},"Using NGINX"),(0,r.yg)("p",null,"If you're using NGINX, then you can use your own domain name, with a config similar to the below example."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"upstream dashy {\n server 127.0.0.1:32400;\n}\n\nserver {\n listen 80;\n server_name dashy.mydomain.com;\n\n # Setup SSL\n ssl_certificate /var/www/mydomain/sslcert.pem;\n ssl_certificate_key /var/www/mydomain/sslkey.pem;\n ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';\n ssl_session_timeout 5m;\n ssl_prefer_server_ciphers on;\n\n location / {\n proxy_pass http://dashy;\n proxy_redirect off;\n proxy_buffering off;\n proxy_set_header host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;\n }\n}\n")),(0,r.yg)("p",null,"Similarly, a basic ",(0,r.yg)("inlineCode",{parentName:"p"},"Caddyfile")," might look like:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"dashy.example.com {\n reverse_proxy / nginx:80\n}\n")),(0,r.yg)("p",null,"For more info, ",(0,r.yg)("a",{parentName:"p",href:"https://thehomelab.wiki/books/dns-reverse-proxy/page/create-domain-records-to-point-to-your-home-server-on-cloudflare-using-nginx-progy-manager"},"this guide")," on Setting up Domains with NGINX Proxy Manager and CloudFlare may be useful."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"container-security"},"Container Security"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#keep-docker-up-to-date"},"Keep Docker Up-To-Date")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#set-resource-quotas"},"Set Resource Quotas")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#dont-run-as-root"},"Don't Run as Root")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#specify-a-user"},"Specify a User")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#limit-capabilities"},"Limit Capabilities")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#prevent-new-privileges-being-added"},"Prevent new Privileges being Added")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#disable-inter-container-communication"},"Disable Inter-Container Communication")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#dont-expose-the-docker-daemon-socket"},"Don't Expose the Docker Daemon Socket")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#use-read-only-volumes"},"Use Read-Only Volumes")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#set-the-logging-level"},"Set the Logging Level")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#verify-image-before-pulling"},"Verify Image before Pulling")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#specify-the-tag"},"Specify the Tag")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#container-security-scanning"},"Container Security Scanning")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#registry-security"},"Registry Security")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#security-modules"},"Security Modules"))),(0,r.yg)("h3",{id:"keep-docker-up-to-date"},"Keep Docker Up-To-Date"),(0,r.yg)("p",null,"To prevent known container escape vulnerabilities, which typically end in escalating to root/administrator privileges, patching Docker Engine and Docker Machine is crucial. For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/install/"},"Docker Installation Docs"),"."),(0,r.yg)("h3",{id:"set-resource-quotas"},"Set Resource Quotas"),(0,r.yg)("p",null,"Docker enables you to limit resource consumption (CPU, memory, disk) on a per-container basis. This not only enhances system performance, but also prevents a compromised container from consuming a large amount of resources, in order to disrupt service or perform malicious activities. To learn more, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/containers/resource_constraints/"},"Resource Constraints Docs")),(0,r.yg)("p",null,"For example, to run Dashy with max of 1GB ram, and max of 50% of 1 CP core:\n",(0,r.yg)("inlineCode",{parentName:"p"},'docker run -d -p 8080:80 --cpus=".5" --memory="1024m" lissy93/dashy:latest')),(0,r.yg)("h3",{id:"dont-run-as-root"},"Don't Run as Root"),(0,r.yg)("p",null,"Running a container with admin privileges gives it more power than it needs, and can be abused. Dashy does not need any root privileges, and Docker by default doesn't run containers as root, so providing you don't specifically type sudo, you should be all good here."),(0,r.yg)("p",null,"Note that if you're facing permission issues on Debian-based systems, you may need to add your user to the Docker group. First create the group: ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo groupadd docker"),", then add your (non-root) user: ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo usermod \u2212aG docker [my-username]"),", finally ",(0,r.yg)("inlineCode",{parentName:"p"},"newgrp docker")," to refresh."),(0,r.yg)("h3",{id:"specify-a-user"},"Specify a User"),(0,r.yg)("p",null,"One of the best ways to prevent privilege escalation attacks, is to configure the container to use an unprivileged user. This also means that any files created by the container and mounted, will be owned by the specified user (and not root), which makes things much easier."),(0,r.yg)("p",null,"You can specify a user, using the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/run/#user"},(0,r.yg)("inlineCode",{parentName:"a"},"--user")," param"),", and should include the user ID (",(0,r.yg)("inlineCode",{parentName:"p"},"UID"),"), which can be found by running ",(0,r.yg)("inlineCode",{parentName:"p"},"id -u"),", and the and the group ID (",(0,r.yg)("inlineCode",{parentName:"p"},"GID"),"), using ",(0,r.yg)("inlineCode",{parentName:"p"},"id -g"),"."),(0,r.yg)("p",null,"With Docker run, you specify it like:\n",(0,r.yg)("inlineCode",{parentName:"p"},"docker run --user 1000:1000 -p 8080:80 lissy93/dashy")),(0,r.yg)("p",null,"Of if you're using Docker-compose, you could use an environmental variable"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},'version: "3.8"\nservices:\n dashy:\n image: lissy93/dashy\n user: ${CURRENT_UID}\n ports: [ 4000:80 ]\n')),(0,r.yg)("p",null,"And then to set the variable, and start the container, run: ",(0,r.yg)("inlineCode",{parentName:"p"},"CURRENT_UID=$(id -u):$(id -g) docker-compose up")),(0,r.yg)("h3",{id:"limit-capabilities"},"Limit capabilities"),(0,r.yg)("p",null,"Docker containers run with a subset of ",(0,r.yg)("a",{parentName:"p",href:"https://man7.org/linux/man-pages/man7/capabilities.7.html"},"Linux Kernal's Capabilities")," by default. It's good practice to drop privilege permissions that are not needed for any given container."),(0,r.yg)("p",null,"With Docker run, you can use the ",(0,r.yg)("inlineCode",{parentName:"p"},"--cap-drop")," flag to remove capabilities, you can also use ",(0,r.yg)("inlineCode",{parentName:"p"},"--cap-drop=all")," and then define just the required permissions using the ",(0,r.yg)("inlineCode",{parentName:"p"},"--cap-add")," option. For a list of available capabilities, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities"},"Privilege Capabilities Docs"),"."),(0,r.yg)("p",null,"Note that dropping privileges and capabilities on runtime is not fool-proof, and often any leftover privileges can be used to re-escalate, see ",(0,r.yg)("a",{parentName:"p",href:"https://wiki.sei.cmu.edu/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges"},"POS36-C"),"."),(0,r.yg)("p",null,"Here's an example using docker-compose, removing privileges that are not required for Dashy to run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},'version: "3.8"\nservices:\n dashy:\n image: lissy93/dashy\n ports: [ 4000:80 ]\n cap_drop:\n - ALL\n cap_add:\n - CHOWN\n - SETGID\n - SETUID\n - DAC_OVERRIDE\n - NET_BIND_SERVICE\n')),(0,r.yg)("h3",{id:"prevent-new-privileges-being-added"},"Prevent new Privileges being Added"),(0,r.yg)("p",null,"To prevent processes inside the container from getting additional privileges, pass in the ",(0,r.yg)("inlineCode",{parentName:"p"},"--security-opt=no-new-privileges:true")," option to the Docker run command (see ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/run/#security-configuration"},"docs"),")."),(0,r.yg)("p",null,"Run Command:\n",(0,r.yg)("inlineCode",{parentName:"p"},"docker run --security-opt=no-new-privileges:true -p 8080:80 lissy93/dashy")),(0,r.yg)("p",null,"Docker Compose"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"security_opt:\n- no-new-privileges:true\n")),(0,r.yg)("h3",{id:"disable-inter-container-communication"},"Disable Inter-Container Communication"),(0,r.yg)("p",null,"By default Docker containers can talk to each other (using ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/containers/container-networking/"},(0,r.yg)("inlineCode",{parentName:"a"},"docker0")," bridged network"),"). If you don't need this capability, then it should be disabled. This can be done with the ",(0,r.yg)("inlineCode",{parentName:"p"},"--icc=false")," in your run command. You can learn more about how to facilitate secure communication between containers in the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/compose/networking/"},"Compose Networking docs"),"."),(0,r.yg)("h3",{id:"dont-expose-the-docker-daemon-socket"},"Don't Expose the Docker Daemon Socket"),(0,r.yg)("p",null,"Docker socket ",(0,r.yg)("inlineCode",{parentName:"p"},"/var/run/docker.sock")," is the UNIX socket that Docker is listening to. This is the primary entry point for the Docker API. The owner of this socket is root. Giving someone access to it is equivalent to giving unrestricted root access to your host."),(0,r.yg)("p",null,"You should ",(0,r.yg)("strong",{parentName:"p"},"not")," enable TCP Docker daemon socket (",(0,r.yg)("inlineCode",{parentName:"p"},"-H tcp://0.0.0.0:XXX"),"), as doing so exposes un-encrypted and unauthenticated direct access to the Docker daemon, and if the host is connected to the internet, the daemon on your computer can be used by anyone from the public internet- which is bad. If you need TCP, you should ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option"},"see the docs")," to understand how to do this more securely.\nSimilarly, never expose ",(0,r.yg)("inlineCode",{parentName:"p"},"/var/run/docker.sock")," to other containers as a volume, as it can be exploited."),(0,r.yg)("h3",{id:"use-read-only-volumes"},"Use Read-Only Volumes"),(0,r.yg)("p",null,"You can specify that a specific volume should be read-only by appending ",(0,r.yg)("inlineCode",{parentName:"p"},":ro")," to the ",(0,r.yg)("inlineCode",{parentName:"p"},"-v")," switch. For example, while running Dashy, if we want our config to be writable, but keep all other assets protected, we would do:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n -p 8080:80 \\\n -v ~/dashy-conf.yml:/app/public/conf.yml \\\n -v ~/dashy-icons:/app/public/item-icons:ro \\\n -v ~/dashy-theme.scss:/app/src/styles/user-defined-themes.scss:ro \\\n lissy93/dashy:latest\n")),(0,r.yg)("p",null,"You can also prevent a container from writing any changes to volumes on your host's disk, using the ",(0,r.yg)("inlineCode",{parentName:"p"},"--read-only")," flag. Although, for Dashy, you will not be able to write config changes to disk, when edited through the UI with this method. You could make this work, by specifying the config directory as a temp write location, with ",(0,r.yg)("inlineCode",{parentName:"p"},"--tmpfs /app/public/conf.yml")," - but that this will not write the volume back to your host."),(0,r.yg)("h3",{id:"set-the-logging-level"},"Set the Logging Level"),(0,r.yg)("p",null,"Logging is important, as it enables you to review events in the future, and in the case of a compromise this will let get an idea of what may have happened. The default log level is ",(0,r.yg)("inlineCode",{parentName:"p"},"INFO"),", and this is also the recommendation, use ",(0,r.yg)("inlineCode",{parentName:"p"},"--log-level info")," to ensure this is set."),(0,r.yg)("h3",{id:"verify-image-before-pulling"},"Verify Image before Pulling"),(0,r.yg)("p",null,"Only use trusted images, from verified/ official sources. If an app is open source, it is more likely to be safe, as anyone can verify the code. There are also tools available for scanning containers,"),(0,r.yg)("p",null,"Unless otherwise configured, containers can communicate among each other, so running one bad image may lead to other areas of your setup being compromised. Docker images typically contain both original code, as well as up-stream packages, and even if that image has come from a trusted source, the up-stream packages it includes may not have."),(0,r.yg)("h3",{id:"specify-the-tag"},"Specify the Tag"),(0,r.yg)("p",null,"Using fixed tags (as opposed to ",(0,r.yg)("inlineCode",{parentName:"p"},":latest")," ) will ensure immutability, meaning the base image will not change between builds. Note that for Dashy, the app is being actively developed, new features, bug fixes and general improvements are merged each week, and if you use a fixed version you will not enjoy these benefits. So it's up to you weather you would prefer a stable and reproducible environment, or the latest features and enhancements."),(0,r.yg)("h3",{id:"container-security-scanning"},"Container Security Scanning"),(0,r.yg)("p",null,"It's helpful to be aware of any potential security issues in any of the Docker images you are using. You can run a quick scan using Snyk on any image to output known vulnerabilities using ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/scan/"},"Docker scan"),", e.g: ",(0,r.yg)("inlineCode",{parentName:"p"},"docker scan lissy93/dashy:latest"),"."),(0,r.yg)("p",null,"A similar product is ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/aquasecurity/trivy"},"Trivy"),", which is free an open source. First install it (with your package manager), then to scan an image, just run: ",(0,r.yg)("inlineCode",{parentName:"p"},"trivy image lissy93/dashy:latest")),(0,r.yg)("p",null,"For larger systems, RedHat ",(0,r.yg)("a",{parentName:"p",href:"https://www.redhat.com/en/topics/containers/what-is-clair"},"Clair")," is an app for parsing image contents and reporting on any found vulnerabilities. You run it locally in a container, and configure it with YAML. It can be integrated with Red Hat Quay, to show results on a dashboard. Most of these use static analysis to find potential issues, and scan included packages for any known security vulnerabilities."),(0,r.yg)("h3",{id:"registry-security"},"Registry Security"),(0,r.yg)("p",null,"Although over-kill for most users, you could run your own registry locally which would give you ultimate control over all images, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/registry/deploying/"},"Deploying a Registry Docs")," for more info. Another option is ",(0,r.yg)("a",{parentName:"p",href:"https://docker-docs.netlify.app/ee/dtr/"},"Docker Trusted Registry"),", it's great for enterprise applications, it sits behind your firewall, running on a swarm managed by Docker Universal Control Plane, and lets you securely store and manage your Docker images, mitigating the risk of breaches from the internet."),(0,r.yg)("h3",{id:"security-modules"},"Security Modules"),(0,r.yg)("p",null,"Docker supports several modules that let you write your own security profiles."),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://www.apparmor.net/"},"AppArmor"),"is a kernel module that proactively protects the operating system and applications from external or internal threats, by enabling you to restrict programs' capabilities with per-program profiles. You can specify either a security policy by name, or by file path with the ",(0,r.yg)("inlineCode",{parentName:"p"},"apparmor")," flag in docker run. Learn more about writing profiles, ",(0,r.yg)("a",{parentName:"p",href:"https://gitlab.com/apparmor/apparmor/-/wikis/QuickProfileLanguage"},"here"),"."),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Seccomp"},"Seccomp")," (Secure Computing Mode) is a sandboxing facility in the Linux kernel that acts like a firewall for system calls (syscalls). It uses Berkeley Packet Filter (BPF) rules to filter syscalls and control how they are handled. These filters can significantly limit a containers access to the Docker Host's Linux kernel - especially for simple containers/applications. It requires a Linux-based Docker host, with secomp enabled, and you can check for this by running ",(0,r.yg)("inlineCode",{parentName:"p"},"docker info | grep seccomp"),". A great resource for learning more about this is ",(0,r.yg)("a",{parentName:"p",href:"https://training.play-with-docker.com/security-seccomp/"},"DockerLabs"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"web-server-configuration"},"Web Server Configuration"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},(0,r.yg)("em",{parentName:"p"},"The following section only applies if you are not using Docker, and would like to use your own web server"))),(0,r.yg)("p",null,"Dashy ships with a pre-configured Node.js server, in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/server.js"},(0,r.yg)("inlineCode",{parentName:"a"},"server.js"))," which serves up the contents of the ",(0,r.yg)("inlineCode",{parentName:"p"},"./dist")," directory on a given port. You can start the server by running ",(0,r.yg)("inlineCode",{parentName:"p"},"node server"),". Note that the app must have been build (run ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn build"),"), and you need ",(0,r.yg)("a",{parentName:"p",href:"https://nodejs.org"},"Node.js")," installed."),(0,r.yg)("p",null,"If you wish to run Dashy from a sub page (e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"example.com/dashy"),"), then just set the ",(0,r.yg)("inlineCode",{parentName:"p"},"BASE_URL")," environmental variable to that page name (in this example, ",(0,r.yg)("inlineCode",{parentName:"p"},"/dashy"),"), before building the app, and the path to all assets will then resolve to the new path, instead of ",(0,r.yg)("inlineCode",{parentName:"p"},"./"),"."),(0,r.yg)("p",null,"However, since Dashy is just a static web application, it can be served with whatever server you like. The following section outlines how you can configure a web server."),(0,r.yg)("p",null,"Note, that if you choose not to use ",(0,r.yg)("inlineCode",{parentName:"p"},"server.js")," to serve up the app, you will loose access to the following features:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Loading page, while the app is building"),(0,r.yg)("li",{parentName:"ul"},"Writing config file to disk from the UI"),(0,r.yg)("li",{parentName:"ul"},"Website status indicators, and ping checks")),(0,r.yg)("p",null,"Example Configs"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nginx"},"NGINX")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#apache"},"Apache")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#caddy"},"Caddy")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#firebase-hosting"},"Firebase")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpanel"},"cPanel"))),(0,r.yg)("h3",{id:"nginx-1"},"NGINX"),(0,r.yg)("p",null,"Create a new file in ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/nginx/sites-enabled/dashy")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"server {\n listen 80;\n listen [::]:80;\n\n root /var/www/dashy/html;\n index index.html;\n\n server_name your-domain.com www.your-domain.com;\n\n location / {\n try_files $uri $uri/ =404;\n }\n}\n")),(0,r.yg)("p",null,"To use HTML5 history mode (",(0,r.yg)("inlineCode",{parentName:"p"},"appConfig.routingMode: history"),"), replace the inside of the location block with: ",(0,r.yg)("inlineCode",{parentName:"p"},"try_files $uri $uri/ /index.html;"),"."),(0,r.yg)("p",null,"Then upload the build contents of Dashy's dist directory to that location.\nFor example: ",(0,r.yg)("inlineCode",{parentName:"p"},"scp -r ./dist/* [username]@[server_ip]:/var/www/dashy/html")),(0,r.yg)("h3",{id:"apache-1"},"Apache"),(0,r.yg)("p",null,"Copy Dashy's dist folder to your apache server, ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo cp -r ./dashy/dist /var/www/html/dashy"),"."),(0,r.yg)("p",null,"In your Apache config, ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/apche2/apache2.conf")," add:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"\n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n\n\n\n RewriteEngine On\n RewriteBase /\n RewriteRule ^index\\.html$ - [L]\n RewriteCond %{REQUEST_FILENAME} !-f\n RewriteCond %{REQUEST_FILENAME} !-d\n RewriteRule . /index.html [L]\n\n")),(0,r.yg)("p",null,"Add a ",(0,r.yg)("inlineCode",{parentName:"p"},".htaccess")," file within ",(0,r.yg)("inlineCode",{parentName:"p"},"/var/www/html/dashy/.htaccess"),", and add:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"Options -MultiViews\nRewriteEngine On\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteRule ^ index.html [QSA,L]\n")),(0,r.yg)("p",null,"Then restart Apache, with ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo systemctl restart apache2")),(0,r.yg)("h3",{id:"caddy-1"},"Caddy"),(0,r.yg)("p",null,"Caddy v2"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"try_files {path} /\n")),(0,r.yg)("p",null,"Caddy v1"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"rewrite {\n regexp .*\n to {path} /\n}\n")),(0,r.yg)("h3",{id:"firebase-hosting"},"Firebase Hosting"),(0,r.yg)("p",null,"Create a file names ",(0,r.yg)("inlineCode",{parentName:"p"},"firebase.json"),", and populate it with something similar to:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},'{\n "hosting": {\n "public": "dist",\n "rewrites": [\n {\n "source": "**",\n "destination": "/index.html"\n }\n ]\n }\n}\n')),(0,r.yg)("h3",{id:"cpanel"},"cPanel"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Login to your WHM"),(0,r.yg)("li",{parentName:"ol"},"Open 'Feature Manager' on the left sidebar"),(0,r.yg)("li",{parentName:"ol"},"Under 'Manage feature list', click 'Edit'"),(0,r.yg)("li",{parentName:"ol"},"Find 'Application manager' in the list, enable it and hit 'Save'"),(0,r.yg)("li",{parentName:"ol"},"Log into your users cPanel account, and under 'Software' find 'Application Manager'"),(0,r.yg)("li",{parentName:"ol"},"Click 'Register Application', fill in the form using the path that Dashy is located, and choose a domain, and hit 'Save'"),(0,r.yg)("li",{parentName:"ol"},"The application should now show up in the list, click 'Ensure dependencies', and move the toggle switch to 'Enabled'"),(0,r.yg)("li",{parentName:"ol"},"If you need to change the port, click 'Add environmental variable', give it the name 'PORT', choose a port number and press 'Save'."),(0,r.yg)("li",{parentName:"ol"},"Dashy should now be running at your selected path an on a given port")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"running-a-modified-version-of-the-app"},"Running a Modified Version of the App"),(0,r.yg)("p",null,"If you'd like to make any code changes to the app, and deploy your modified version, this section briefly explains how."),(0,r.yg)("p",null,"The first step is to fork the project on GitHub, and clone it to your local system. Next, install the dependencies (",(0,r.yg)("inlineCode",{parentName:"p"},"yarn"),"), and start the development server (",(0,r.yg)("inlineCode",{parentName:"p"},"yarn dev"),") and visit ",(0,r.yg)("inlineCode",{parentName:"p"},"localhost:8080")," in your browser. You can then make changes to the codebase, and see the live app update in real-time. Once you've finished, running ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn build")," will build the app for production, and output the assets into ",(0,r.yg)("inlineCode",{parentName:"p"},"./dist")," which can then be deployed using a web server, CDN or the built-in Node server with ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn start"),". For more info on all of this, take a look at the ",(0,r.yg)("a",{parentName:"p",href:"/docs/developing"},"Developing Docs"),". To build your own Docker container from the modified app, see ",(0,r.yg)("a",{parentName:"p",href:"#building-your-own-container"},"Building your Own Container")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"building-your-own-container"},"Building your Own Container"),(0,r.yg)("p",null,"Similar to above, you'll first need to fork and clone Dashy to your local system, and then install dependencies."),(0,r.yg)("p",null,"Then, either use Dashy's default ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/Dockerfile"},(0,r.yg)("inlineCode",{parentName:"a"},"Dockerfile"))," as is, or modify it according to your needs."),(0,r.yg)("p",null,"To build and deploy locally, first build the app with: ",(0,r.yg)("inlineCode",{parentName:"p"},"docker build -t dashy ."),", and then start the app with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker run -p 8080:80 --name my-dashboard dashy"),". Or modify the ",(0,r.yg)("inlineCode",{parentName:"p"},"docker-compose.yml")," file, replacing ",(0,r.yg)("inlineCode",{parentName:"p"},"image: lissy93/dashy")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"build: .")," and run ",(0,r.yg)("inlineCode",{parentName:"p"},"docker compose up"),"."),(0,r.yg)("p",null,"Your container should now be running, and will appear in the list when you run ",(0,r.yg)("inlineCode",{parentName:"p"},"docker container ls \u2013a"),". If you'd like to enter the container, run ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it [container-id] /bin/ash"),"."),(0,r.yg)("p",null,"You may wish to upload your image to a container registry for easier access. Note that if you choose to do this on a public registry, please name your container something other than just 'dashy', to avoid confusion with the official image.\nYou can push your build image, by running: ",(0,r.yg)("inlineCode",{parentName:"p"},"docker push ghcr.io/OWNER/IMAGE_NAME:latest"),". You will first need to authenticate, this can be done by running ",(0,r.yg)("inlineCode",{parentName:"p"},"echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin"),", where ",(0,r.yg)("inlineCode",{parentName:"p"},"CR_PAT")," is an environmental variable containing a token generated from your GitHub account. For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry"},"Container Registry Docs"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#management"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1f5fb0df.3ab253cd.js b/assets/js/1f5fb0df.3ab253cd.js new file mode 100644 index 00000000..ff60e567 --- /dev/null +++ b/assets/js/1f5fb0df.3ab253cd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[695],{5680:(e,n,a)=>{a.d(n,{xA:()=>c,yg:()=>h});var t=a(6540);function r(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function o(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function i(e){for(var n=1;n=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=t.createContext({}),p=function(e){var n=t.useContext(l),a=n;return e&&(a="function"==typeof e?e(n):i(i({},n),e)),a},c=function(e){var n=p(e.components);return t.createElement(l.Provider,{value:n},e.children)},g="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},d=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),g=p(a),d=r,h=g["".concat(l,".").concat(d)]||g[d]||u[d]||o;return a?t.createElement(h,i(i({ref:n},c),{},{components:a})):t.createElement(h,i({ref:n},c))}));function h(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[g]="string"==typeof e?e:r,i[1]=s;for(var p=2;p{a.r(n),a.d(n,{contentTitle:()=>i,default:()=>g,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var t=a(8168),r=(a(6540),a(5680));const o={},i="App Management",s={unversionedId:"management",id:"management",isDocsHomePage:!1,title:"App Management",description:"The following article is a primer on managing self-hosted apps. It covers everything from keeping the Dashy (or any other app) up-to-date, secure, backed up, to other topics like auto-starting, monitoring, log management, web server configuration and using custom domains.",source:"@site/docs/management.md",sourceDirName:".",slug:"/management",permalink:"/docs/management",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/management.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Configuring",permalink:"/docs/configuring"},next:{title:"Troubleshooting",permalink:"/docs/troubleshooting"}},l=[{value:"Contents",id:"contents",children:[]},{value:"Providing Assets",id:"providing-assets",children:[]},{value:"Running Commands",id:"running-commands",children:[]},{value:"Healthchecks",id:"healthchecks",children:[]},{value:"Logs and Performance",id:"logs-and-performance",children:[{value:"Container Logs",id:"container-logs",children:[]},{value:"Container Performance",id:"container-performance",children:[]},{value:"Management Apps",id:"management-apps",children:[]},{value:"Advanced Logging and Monitoring",id:"advanced-logging-and-monitoring",children:[]}]},{value:"Auto-Starting at System Boot",id:"auto-starting-at-system-boot",children:[]},{value:"Updating",id:"updating",children:[{value:"Updating Docker Container",id:"updating-docker-container",children:[]},{value:"Automatic Docker Updates",id:"automatic-docker-updates",children:[]},{value:"Updating Dashy from Source",id:"updating-dashy-from-source",children:[]}]},{value:"Backing Up",id:"backing-up",children:[{value:"Backing Up Containers",id:"backing-up-containers",children:[]},{value:"Backing Up Volumes",id:"backing-up-volumes",children:[]},{value:"Dashy-Specific Backup",id:"dashy-specific-backup",children:[]}]},{value:"Scheduling",id:"scheduling",children:[]},{value:"SSL Certificates",id:"ssl-certificates",children:[{value:"Auto-SSL",id:"auto-ssl",children:[]},{value:"Getting a Self-Signed SSL Certificate",id:"getting-a-self-signed-ssl-certificate",children:[]},{value:"Passing a Self-Signed Certificate to Dashy",id:"passing-a-self-signed-certificate-to-dashy",children:[]}]},{value:"Authentication",id:"authentication",children:[]},{value:"Managing Containers with Docker Compose",id:"managing-containers-with-docker-compose",children:[]},{value:"Passing in Environmental Variables",id:"passing-in-environmental-variables",children:[]},{value:"Setting Headers",id:"setting-headers",children:[{value:"Example Headers",id:"example-headers",children:[]}]},{value:"Remote Access",id:"remote-access",children:[{value:"WireGuard",id:"wireguard",children:[]},{value:"Reverse SSH Tunnel",id:"reverse-ssh-tunnel",children:[]},{value:"TCP Tunnel",id:"tcp-tunnel",children:[]}]},{value:"Custom Domain",id:"custom-domain",children:[{value:"Using DNS",id:"using-dns",children:[]},{value:"Using NGINX",id:"using-nginx",children:[]}]},{value:"Container Security",id:"container-security",children:[{value:"Keep Docker Up-To-Date",id:"keep-docker-up-to-date",children:[]},{value:"Set Resource Quotas",id:"set-resource-quotas",children:[]},{value:"Don't Run as Root",id:"dont-run-as-root",children:[]},{value:"Specify a User",id:"specify-a-user",children:[]},{value:"Limit capabilities",id:"limit-capabilities",children:[]},{value:"Prevent new Privileges being Added",id:"prevent-new-privileges-being-added",children:[]},{value:"Disable Inter-Container Communication",id:"disable-inter-container-communication",children:[]},{value:"Don't Expose the Docker Daemon Socket",id:"dont-expose-the-docker-daemon-socket",children:[]},{value:"Use Read-Only Volumes",id:"use-read-only-volumes",children:[]},{value:"Set the Logging Level",id:"set-the-logging-level",children:[]},{value:"Verify Image before Pulling",id:"verify-image-before-pulling",children:[]},{value:"Specify the Tag",id:"specify-the-tag",children:[]},{value:"Container Security Scanning",id:"container-security-scanning",children:[]},{value:"Registry Security",id:"registry-security",children:[]},{value:"Security Modules",id:"security-modules",children:[]}]},{value:"Web Server Configuration",id:"web-server-configuration",children:[{value:"NGINX",id:"nginx-1",children:[]},{value:"Apache",id:"apache-1",children:[]},{value:"Caddy",id:"caddy-1",children:[]},{value:"Firebase Hosting",id:"firebase-hosting",children:[]},{value:"cPanel",id:"cpanel",children:[]}]},{value:"Running a Modified Version of the App",id:"running-a-modified-version-of-the-app",children:[]},{value:"Building your Own Container",id:"building-your-own-container",children:[]}],p={toc:l},c="wrapper";function g(e){let{components:n,...a}=e;return(0,r.yg)(c,(0,t.A)({},p,a,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"app-management"},"App Management"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"The following article is a primer on managing self-hosted apps. It covers everything from keeping the Dashy (or any other app) up-to-date, secure, backed up, to other topics like auto-starting, monitoring, log management, web server configuration and using custom domains.")),(0,r.yg)("h2",{id:"contents"},"Contents"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#providing-assets"},"Providing Assets")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#running-commands"},"Running Commands")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#healthchecks"},"Healthchecks")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#logs-and-performance"},"Logs and Performance")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#auto-starting-at-system-boot"},"Auto-Starting at Boot")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#updating"},"Updating")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#backing-up"},"Backing Up")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#scheduling"},"Scheduling")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#ssl-certificates"},"SSL Certificates")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#authentication"},"Authentication")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#managing-containers-with-docker-compose"},"Managing with Compose")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#passing-in-environmental-variables"},"Environmental Variables")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#setting-headers"},"Setting Headers")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#remote-access"},"Remote Access")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#custom-domain"},"Custom Domain")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#container-security"},"Securing Containers")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#web-server-configuration"},"Web Server Configuration")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#running-a-modified-version-of-the-app"},"Running a Modified App")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#building-your-own-container"},"Building your Own Container"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"providing-assets"},"Providing Assets"),(0,r.yg)("p",null,"Although not essential, you will most likely want to provide several assets to your running app."),(0,r.yg)("p",null,"This is easy to do using ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/storage/volumes/"},"Docker Volumes"),", which lets you share a file or directory between your host system, and the container. Volumes are specified in the Docker run command, or Docker compose file, using the ",(0,r.yg)("inlineCode",{parentName:"p"},"--volume")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"-v")," flags. The value of which consists of the path to the file / directory on your host system, followed by the destination path within the container. Fields are separated by a colon (",(0,r.yg)("inlineCode",{parentName:"p"},":"),"), and must be in the correct order. For example: ",(0,r.yg)("inlineCode",{parentName:"p"},"-v ~/alicia/my-local-conf.yml:/app/public/conf.yml")),(0,r.yg)("p",null,"In Dashy, commonly configured resources include:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"./public/conf.yml")," - Your main application config file"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"./public/item-icons")," - A directory containing your own icons. This allows for offline access, and better performance than fetching from a CDN"),(0,r.yg)("li",{parentName:"ul"},"Also within ",(0,r.yg)("inlineCode",{parentName:"li"},"./public")," you'll find standard website assets, including ",(0,r.yg)("inlineCode",{parentName:"li"},"favicon.ico"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"manifest.json"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"robots.txt"),", etc. There's no need to pass these in, but you can do so if you wish"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"/src/styles/user-defined-themes.scss")," - A stylesheet for applying custom CSS to your app. You can also write your own themes here.")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"running-commands"},"Running Commands"),(0,r.yg)("p",null,"If you're running an app in Docker, then commands will need to be passed to the container to be executed. This can be done by preceding each command with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it [container-id]"),", where container ID can be found by running ",(0,r.yg)("inlineCode",{parentName:"p"},"docker ps"),". For example ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it 26c156c467b4 yarn build"),". You can also enter the container, with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it [container-id] /bin/ash"),", and navigate around it with normal Linux commands."),(0,r.yg)("p",null,"Dashy has several commands that can be used for various tasks, you can find a list of these either in the ",(0,r.yg)("a",{parentName:"p",href:"/docs/developing#project-commands"},"Developing Docs"),", or by looking at the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/package.json#L5"},(0,r.yg)("inlineCode",{parentName:"a"},"package.json")),". These can be used by running ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn [command-name]"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"healthchecks"},"Healthchecks"),(0,r.yg)("p",null,"Healthchecks are configured to periodically check that Dashy is up and running correctly on the specified port. By default, the health script is called every 5 minutes, but this can be modified with the ",(0,r.yg)("inlineCode",{parentName:"p"},"--health-interval")," option. You can check the current container health with: ",(0,r.yg)("inlineCode",{parentName:"p"},'docker inspect --format "{{json .State.Health }}" [container-id]'),", and a summary of health status will show up under ",(0,r.yg)("inlineCode",{parentName:"p"},"docker ps"),". You can also manually request the current application status by running ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it [container-id] yarn health-check"),". You can disable healthchecks altogether by adding the ",(0,r.yg)("inlineCode",{parentName:"p"},"--no-healthcheck")," flag to your Docker run command."),(0,r.yg)("p",null,"To restart unhealthy containers automatically, check out ",(0,r.yg)("a",{parentName:"p",href:"https://hub.docker.com/r/willfarrell/autoheal/"},"Autoheal"),". This image watches for unhealthy containers, and automatically triggers a restart. (This is a stand in for Docker's ",(0,r.yg)("inlineCode",{parentName:"p"},"--exit-on-unhealthy")," that was proposed, but ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/moby/moby/pull/22719"},"not merged"),"). There's also ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/qdm12/deunhealth"},"Deunhealth"),", which is super light-weight, and doesn't require network access."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n --name autoheal \\\n --restart=always \\\n -e AUTOHEAL_CONTAINER_LABEL=all \\\n -v /var/run/docker.sock:/var/run/docker.sock \\\n willfarrell/autoheal\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"logs-and-performance"},"Logs and Performance"),(0,r.yg)("h3",{id:"container-logs"},"Container Logs"),(0,r.yg)("p",null,"You can view logs for a given Docker container with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker logs [container-id]"),", add the ",(0,r.yg)("inlineCode",{parentName:"p"},"--follow")," flag to stream the logs. For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/containers/logging/"},"Logging Documentation"),". There's also ",(0,r.yg)("a",{parentName:"p",href:"https://dozzle.dev/"},"Dozzle"),", a useful tool, that provides a web interface where you can stream and query logs from all your running containers from a single web app."),(0,r.yg)("h3",{id:"container-performance"},"Container Performance"),(0,r.yg)("p",null,"You can check the resource usage for your running Docker containers with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker stats")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"docker stats [container-id]"),". For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/stats/"},"Stats Documentation"),". There's also ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/google/cadvisor"},"cAdvisor"),", a useful web app for viewing and analyzing resource usage and performance of all your running containers."),(0,r.yg)("h3",{id:"management-apps"},"Management Apps"),(0,r.yg)("p",null,"You can also view logs, resource usage and other info as well as manage your entire Docker workflow in third-party Docker management apps. For example ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/portainer/portainer"},"Portainer")," an all-in-one open source management web UI for Docker and Kubernetes, or ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/jesseduffield/lazydocker"},"LazyDocker")," a terminal UI for Docker container management and monitoring."),(0,r.yg)("h3",{id:"advanced-logging-and-monitoring"},"Advanced Logging and Monitoring"),(0,r.yg)("p",null,"Docker supports using ",(0,r.yg)("a",{parentName:"p",href:"https://prometheus.io/"},"Prometheus")," to collect logs, which can then be visualized using a platform like ",(0,r.yg)("a",{parentName:"p",href:"https://grafana.com/"},"Grafana"),". For more info, see ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/daemon/prometheus/"},"this guide"),". If you need to route your logs to a remote syslog, then consider using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/gliderlabs/logspout"},"logspout"),". For enterprise-grade instances, there are managed services, that make monitoring container logs and metrics very easy, such as ",(0,r.yg)("a",{parentName:"p",href:"https://sematext.com/blog/docker-container-monitoring-with-sematext/"},"Sematext")," with ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/sematext/logagent-js"},"Logagent"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"auto-starting-at-system-boot"},"Auto-Starting at System Boot"),(0,r.yg)("p",null,"You can use Docker's ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/run/#restart-policies---restart"},"restart policies")," to instruct the container to start after a system reboot, or restart after a crash. Just add the ",(0,r.yg)("inlineCode",{parentName:"p"},"--restart=always")," flag to your Docker compose script or Docker run command. For more information, see the docs on ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/containers/start-containers-automatically/"},"Starting Containers Automatically"),"."),(0,r.yg)("p",null,"For Podman, you can use ",(0,r.yg)("inlineCode",{parentName:"p"},"systemd")," to create a service that launches your container, ",(0,r.yg)("a",{parentName:"p",href:"https://podman.io/blogs/2018/09/13/systemd.html"},"the docs")," explains things further. A similar approach can be used with Docker, if you need to start containers after a reboot, but before any user interaction."),(0,r.yg)("p",null,"To restart the container after something within it has crashed, consider using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/willfarrell/docker-autoheal"},(0,r.yg)("inlineCode",{parentName:"a"},"docker-autoheal"))," by @willfarrell, a service that monitors and restarts unhealthy containers. For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"#healthchecks"},"Healthchecks")," section above."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"updating"},"Updating"),(0,r.yg)("p",null,"Dashy is under active development, so to take advantage of the latest features, you may need to update your instance every now and again."),(0,r.yg)("h3",{id:"updating-docker-container"},"Updating Docker Container"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Pull latest image: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker pull lissy93/dashy:latest")),(0,r.yg)("li",{parentName:"ol"},"Kill off existing container",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Find container ID: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker ps")),(0,r.yg)("li",{parentName:"ul"},"Stop container: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker stop [container_id]")),(0,r.yg)("li",{parentName:"ul"},"Remove container: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker rm [container_id]")))),(0,r.yg)("li",{parentName:"ol"},"Spin up new container: ",(0,r.yg)("inlineCode",{parentName:"li"},"docker run [params] lissy93/dashy"))),(0,r.yg)("h3",{id:"automatic-docker-updates"},"Automatic Docker Updates"),(0,r.yg)("p",null,"You can automate the above process using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/containrrr/watchtower"},"Watchtower"),".\nWatchtower will watch for new versions of a given image on Docker Hub, pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially."),(0,r.yg)("p",null,"To get started, spin up the watchtower container:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n --name watchtower \\\n -v /var/run/docker.sock:/var/run/docker.sock \\\n containrrr/watchtower\n")),(0,r.yg)("p",null,"For more information, see the ",(0,r.yg)("a",{parentName:"p",href:"https://containrrr.dev/watchtower/"},"Watchtower Docs")),(0,r.yg)("h3",{id:"updating-dashy-from-source"},"Updating Dashy from Source"),(0,r.yg)("p",null,"Stop your current instance of Dashy, then navigate into the source directory. Pull down the latest code, with ",(0,r.yg)("inlineCode",{parentName:"p"},"git pull origin master"),", then update dependencies with ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn"),", rebuild with ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn build"),", and start the server again with ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn start"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"backing-up"},"Backing Up"),(0,r.yg)("h3",{id:"backing-up-containers"},"Backing Up Containers"),(0,r.yg)("p",null,"You can make a backup of any running container really easily, using ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/commit/"},(0,r.yg)("inlineCode",{parentName:"a"},"docker commit"))," and save it with ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/export/"},(0,r.yg)("inlineCode",{parentName:"a"},"docker export")),", to do so:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"First find the container ID, you can do this with ",(0,r.yg)("inlineCode",{parentName:"li"},"docker container ls")),(0,r.yg)("li",{parentName:"ul"},"Now to create the snapshot, just run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker commit -p [container-id] my-backup")),(0,r.yg)("li",{parentName:"ul"},"Finally, to save the backup locally, run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker save -o ~/dashy-backup.tar my-backup")),(0,r.yg)("li",{parentName:"ul"},"If you want to push this to a container registry, run ",(0,r.yg)("inlineCode",{parentName:"li"},"docker push my-backup:latest"))),(0,r.yg)("p",null,"Note that this will not include any data in docker volumes, and the process here is a bit different. Since these files exist on your host system, if you have an existing backup solution implemented, you can incorporate and volume files within that system."),(0,r.yg)("h3",{id:"backing-up-volumes"},"Backing Up Volumes"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://github.com/offen/docker-volume-backup"},"offen/docker-volume-backup")," is a useful tool for periodic Docker volume backups, to any S3-compatible storage provider. It's run as a light-weight Docker container, and is easy to setup, and also supports GPG-encryption, email notification, and routing away older backups."),(0,r.yg)("p",null,"To get started, create a docker-compose similar to the example below, and then start the container. For more info, check out their ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/offen/docker-volume-backup"},"documentation"),", which is very clear."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"version: '3'\nservices:\n backup:\n image: offen/docker-volume-backup:latest\n environment:\n BACKUP_CRON_EXPRESSION: \"0 * * * *\"\n BACKUP_PRUNING_PREFIX: backup-\n BACKUP_RETENTION_DAYS: 7\n AWS_BUCKET_NAME: backup-bucket\n AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE\n AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n volumes:\n - data:/backup/my-app-backup:ro\n - /var/run/docker.sock:/var/run/docker.sock:ro\nvolumes:\n data:\n")),(0,r.yg)("p",null,"It's worth noting that this process can also be done manually, using the following commands:"),(0,r.yg)("p",null,"Backup:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run --rm -v some_volume:/volume -v /tmp:/backup alpine tar -cjf /backup/some_archive.tar.bz2 -C /volume ./\n")),(0,r.yg)("p",null,"Restore:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},'docker run --rm -v some_volume:/volume -v /tmp:/backup alpine sh -c "rm -rf /volume/* /volume/..?* /volume/.[!.]* ; tar -C /volume/ -xjf /backup/some_archive.tar.bz2"\n')),(0,r.yg)("h3",{id:"dashy-specific-backup"},"Dashy-Specific Backup"),(0,r.yg)("p",null,"Since Dashy is open source, and freely available, providing you're configuration data is passed in as volumes, there shouldn't be any need to backup the main container. Your main config file, and any assets you're using should be kept backed up, preferably in at least two places, and you should ensure that you can easily restore from backup, if needed."),(0,r.yg)("p",null,"Dashy also has a built-in cloud backup feature, which is free for personal users, and will let you make and restore fully encrypted backups of your config directly through the UI. To learn more, see the ",(0,r.yg)("a",{parentName:"p",href:"/docs/backup-restore"},"Cloud Backup Docs")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"scheduling"},"Scheduling"),(0,r.yg)("p",null,"If you need to periodically schedule the running of a given command on Dashy (or any other container), then a useful tool for doing so it ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/mcuadros/ofelia"},"ofelia"),". This runs as a Docker container and is really useful for things like backups, logging, updating, notifications, etc. Crons are specified using Go's crontab format, and a useful tool for visualizing this is ",(0,r.yg)("a",{parentName:"p",href:"https://crontab.guru/"},"crontab.guru"),". This can also be done natively with Alpine: ",(0,r.yg)("inlineCode",{parentName:"p"},"docker run -it alpine ls /etc/periodic"),".\nI recommend combining this with ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/healthchecks/healthchecks"},"healthchecks")," for easy monitoring of jobs, and failure notifications."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"ssl-certificates"},"SSL Certificates"),(0,r.yg)("p",null,"Enabling HTTPS with an SSL certificate is recommended, especially if you are hosting Dashy anywhere other than your home. This will ensure that all traffic is encrypted in transit."),(0,r.yg)("h3",{id:"auto-ssl"},"Auto-SSL"),(0,r.yg)("p",null,"If you are using ",(0,r.yg)("a",{parentName:"p",href:"https://nginxproxymanager.com/"},"NGINX Proxy Manager"),', then SSL is supported out of the box. Once you\'ve added your proxy host and web address, then set the scheme to HTTPS, then under the SSL Tab select "Request a new SSL certificate" and follow the on-screen instructions.'),(0,r.yg)("p",null,"If you're hosting Dashy behind Cloudflare, then they offer ",(0,r.yg)("a",{parentName:"p",href:"https://www.cloudflare.com/en-gb/learning/ssl/what-is-an-ssl-certificate/"},"free and easy SSL"),"- all you need to do is enable it under the SSL/TLS tab. Or if you are using shared hosting, you may find ",(0,r.yg)("a",{parentName:"p",href:"https://www.sitepoint.com/a-guide-to-setting-up-lets-encrypt-ssl-on-shared-hosting/"},"this tutorial")," helpful."),(0,r.yg)("h3",{id:"getting-a-self-signed-ssl-certificate"},"Getting a Self-Signed SSL Certificate"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://letsencrypt.org/docs/"},"Let's Encrypt")," is a global Certificate Authority, providing free SSL/TLS Domain Validation certificates in order to enable secure HTTPS access to your website. They have good browser/ OS ",(0,r.yg)("a",{parentName:"p",href:"https://letsencrypt.org/docs/certificate-compatibility/"},"compatibility")," with their ISRG X1 and DST CA X3 root certificates, support ",(0,r.yg)("a",{parentName:"p",href:"https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578"},"Wildcard issuance")," done via ACMEv2 using the DNS-01 and have ",(0,r.yg)("a",{parentName:"p",href:"https://letsencrypt.org/2020/02/19/multi-perspective-validation.html"},"Multi-Perspective Validation"),". Let's Encrypt provide ",(0,r.yg)("a",{parentName:"p",href:"https://certbot.eff.org/"},"CertBot")," an easy app for generating and setting up an SSL certificate."),(0,r.yg)("p",null,"This process can be automated, using something like the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Valian/docker-nginx-auto-ssl"},"Docker-NGINX-Auto-SSL Container")," to generate and renew certificates when needed."),(0,r.yg)("p",null,"If you're not so comfortable on the command line, then you can use a tool like ",(0,r.yg)("a",{parentName:"p",href:"https://www.sslforfree.com/"},"SSL For Free")," or ",(0,r.yg)("a",{parentName:"p",href:"https://zerossl.com/"},"ZeroSSL")," to generate your cert. They also provide step-by-step setup instructions for most platforms."),(0,r.yg)("h3",{id:"passing-a-self-signed-certificate-to-dashy"},"Passing a Self-Signed Certificate to Dashy"),(0,r.yg)("p",null,"Once you've generated your SSL cert, you'll need to pass it to Dashy. This can be done by specifying the paths to your public and private keys using the ",(0,r.yg)("inlineCode",{parentName:"p"},"SSL_PRIV_KEY_PATH")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"SSL_PUB_KEY_PATH")," environmental variables. Or if you're using Docker, then just pass public + private SSL keys in under ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/ssl/certs/dashy-pub.pem")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/ssl/certs/dashy-priv.key")," respectively, e.g:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n -p 8080:80 \\\n -v ~/my-private-key.key:/etc/ssl/certs/dashy-priv.key:ro \\\n -v ~/my-public-key.pem:/etc/ssl/certs/dashy-pub.pem:ro \\\n lissy93/dashy:latest\n")),(0,r.yg)("p",null,"By default the SSL port is ",(0,r.yg)("inlineCode",{parentName:"p"},"443")," within a Docker container, or ",(0,r.yg)("inlineCode",{parentName:"p"},"4001")," if running on bare metal, but you can override this with the ",(0,r.yg)("inlineCode",{parentName:"p"},"SSL_PORT")," environmental variable."),(0,r.yg)("p",null,"Once everything is setup, you can verify your site is secured using a tool like ",(0,r.yg)("a",{parentName:"p",href:"https://www.sslchecker.com/sslchecker"},"SSL Checker"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"authentication"},"Authentication"),(0,r.yg)("p",null,"Dashy natively supports secure authentication using KeyCloak. There is also a Simple Auth feature that doesn't require any additional setup. Usage instructions for both, as well as alternative auth methods, has now moved to the ",(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"/docs/authentication"},"Authentication Docs"))," page."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"managing-containers-with-docker-compose"},"Managing Containers with Docker Compose"),(0,r.yg)("p",null,"When you have a lot of containers, it quickly becomes hard to manage with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker run")," commands. The solution to this is ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/compose/"},"docker compose"),", a handy tool for defining all a containers run settings in a single YAML file, and then spinning up that container with a single short command - ",(0,r.yg)("inlineCode",{parentName:"p"},"docker compose up"),". A good example of which can be seen in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/abhilesh/self-hosted_docker_setups"},"@abhilesh's docker compose collection"),"."),(0,r.yg)("p",null,"You can use Dashy's default ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docker-compose.yml"},(0,r.yg)("inlineCode",{parentName:"a"},"docker-compose.yml"))," file as a template, and modify it according to your needs."),(0,r.yg)("p",null,"An example Docker compose, using the default base image from DockerHub, might look something like this:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"---\nversion: \"3.8\"\nservices:\n dashy:\n container_name: Dashy\n image: lissy93/dashy\n volumes:\n - /root/my-config.yml:/app/public/conf.yml\n ports:\n - 4000:80\n environment:\n - BASE_URL=/my-dashboard\n restart: unless-stopped\n healthcheck:\n test: ['CMD', 'node', '/app/services/healthcheck']\n interval: 1m30s\n timeout: 10s\n retries: 3\n start_period: 40s\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"passing-in-environmental-variables"},"Passing in Environmental Variables"),(0,r.yg)("p",null,"With Docker, you can define environmental variables under the ",(0,r.yg)("inlineCode",{parentName:"p"},"environment")," section of your Docker compose file. Environmental variables are used to configure high-level settings, usually before the config file has been read. For a list of all supported env vars in Dashy, see ",(0,r.yg)("a",{parentName:"p",href:"/docs/developing#environmental-variables"},"the developing docs"),", or the default ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/.env"},(0,r.yg)("inlineCode",{parentName:"a"},".env"))," file."),(0,r.yg)("p",null,"A common use case, is to run Dashy under a sub-page, instead of at the root of a URL (e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"https://my-homelab.local/dashy")," instead of ",(0,r.yg)("inlineCode",{parentName:"p"},"https://dashy.my-homelab.local"),"). In this use-case, you'd specify the ",(0,r.yg)("inlineCode",{parentName:"p"},"BASE_URL")," variable in your compose file."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"environment:\n - BASE_URL=/dashy\n")),(0,r.yg)("p",null,"You can also do the same thing with the docker run command, using the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file"},(0,r.yg)("inlineCode",{parentName:"a"},"--env"))," flag.\nIf you've got many environmental variables, you might find it useful to put them in a ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/compose/env-file/"},(0,r.yg)("inlineCode",{parentName:"a"},".env")," file"),". Similarly, for Docker run you can use ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file"},(0,r.yg)("inlineCode",{parentName:"a"},"--env-file"))," if you'd like to pass in a file containing all your environmental variables."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"setting-headers"},"Setting Headers"),(0,r.yg)("p",null,"Any external requests made to a different origin (app/ service under a different domain) will be blocked if the correct headers are not specified. This is known as ",(0,r.yg)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"Cross-Origin Resource Sharing")," (CORS) and is a security feature built into modern browsers."),(0,r.yg)("p",null,"If you see a CORS error in your console, this can be easily fixed by setting the correct headers. This is not a bug with Dashy, so please don't raise it as a bug!"),(0,r.yg)("h3",{id:"example-headers"},"Example Headers"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#caddy"},"Caddy")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nginx"},"NGINX")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#traefik"},"Tr\xe6f\u026ak")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#haproxy"},"HAProxy")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#apache"},"Apache"))),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"The following section briefly outlines how you can set headers for common web proxies/ servers. More info can be found in the documentation for the proxy that you are using, or in the ",(0,r.yg)("a",{parentName:"em",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"MDN Docs"),".")),(0,r.yg)("p",null,"These examples are using:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Access-Control-Allow-Origin")," header, but depending on what type of content you are enabling, this will vary. For example, to allow a site to be loaded in an iframe (for the modal or workspace views) you would use ",(0,r.yg)("inlineCode",{parentName:"li"},"X-Frame-Options"),"."),(0,r.yg)("li",{parentName:"ul"},"The domain root (",(0,r.yg)("inlineCode",{parentName:"li"},"/"),"), if your're hosting from a sub-page, replace that with your path."),(0,r.yg)("li",{parentName:"ul"},"A wildcard (",(0,r.yg)("inlineCode",{parentName:"li"},"*"),"), which would allow access from traffic on any domain, this is discouraged, and you should replace it with the URL where you are hosting Dashy. Note that for requests that transport sensitive info, like credentials (e.g. Keycloak login), the wildcard is ",(0,r.yg)("a",{parentName:"li",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#requests_with_credentials"},"disallowed all together")," and will be blocked.")),(0,r.yg)("h4",{id:"caddy"},"Caddy"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://caddyserver.com/docs/caddyfile/directives/header"},"Caddy ",(0,r.yg)("inlineCode",{parentName:"a"},"header")," docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"headers / {\n Access-Control-Allow-Origin *\n}\n")),(0,r.yg)("h4",{id:"nginx"},"NGINX"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://nginx.org/en/docs/http/ngx_http_headers_module.html"},"NGINX ",(0,r.yg)("inlineCode",{parentName:"a"},"ngx_http_headers_module")," docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"location / {\n add_header Access-Control-Allow-Origin *;\n}\n")),(0,r.yg)("p",null,"Note this can also be done through the UI, using NGINX Proxy Manager."),(0,r.yg)("h4",{id:"traefik"},"Traefik"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://doc.traefik.io/traefik/middlewares/http/headers/#cors-headers"},"Tr\xe6f\u026ak CORS headers docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},'labels:\n - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"\n - "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org"\n - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"\n - "traefik.http.middlewares.testheader.headers.addvaryheader=true"\n')),(0,r.yg)("h4",{id:"haproxy"},"HAProxy"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://www.haproxy.com/documentation/hapee/latest/traffic-routing/rewrites/rewrite-responses/"},"HAProxy Rewrite Response Docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"/\n http-response add-header Access-Control-Allow-Origin *\n")),(0,r.yg)("h4",{id:"apache"},"Apache"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"https://httpd.apache.org/docs/current/mod/mod_headers.html"},"Apache ",(0,r.yg)("inlineCode",{parentName:"a"},"mode_headers")," docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},'Header always set Access-Control-Allow-Origin "*"\n')),(0,r.yg)("h4",{id:"squid"},"Squid"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"See ",(0,r.yg)("a",{parentName:"p",href:"http://www2.gr.squid-cache.org/Doc/config/request_header_access/"},"Squid ",(0,r.yg)("inlineCode",{parentName:"a"},"request_header_access")," docs")," for more info.")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"request_header_access Authorization allow all\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"remote-access"},"Remote Access"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#wireguard"},"WireGuard")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#reverse-ssh-tunnel"},"Reverse SSH Tunnel")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#tcp-tunnel"},"TCP Tunnel"))),(0,r.yg)("h3",{id:"wireguard"},"WireGuard"),(0,r.yg)("p",null,"Using a VPN is one of the easiest ways to provide secure, full access to your local network from remote locations. ",(0,r.yg)("a",{parentName:"p",href:"https://www.wireguard.com/"},"WireGuard")," is a reasonably new open source VPN protocol, that was designed with ease of use, performance and security in mind. Unlike OpenVPN, it doesn't need to recreate the tunnel whenever connection is dropped, and it's also much easier to setup, using shared keys instead."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Install Wireguard")," - See the ",(0,r.yg)("a",{parentName:"li",href:"https://www.wireguard.com/install/"},"Install Docs")," for download links + instructions",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"On Debian-based systems, it's ",(0,r.yg)("inlineCode",{parentName:"li"},"sudo apt install wireguard")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Generate a Private Key")," - Run ",(0,r.yg)("inlineCode",{parentName:"li"},"wg genkey")," on the Wireguard server, and copy it to somewhere safe for later"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Create Server Config")," - Open or create a file at ",(0,r.yg)("inlineCode",{parentName:"li"},"/etc/wireguard/wg0.conf")," and under ",(0,r.yg)("inlineCode",{parentName:"li"},"[Interface]")," add the following (see example below):",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Address")," - as a subnet of all desired IPs"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"PrivateKey")," - that you just generated"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"ListenPort")," - Default is ",(0,r.yg)("inlineCode",{parentName:"li"},"51820"),", but can be anything"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Get Client App")," - Download the ",(0,r.yg)("a",{parentName:"li",href:"https://www.wireguard.com/install/"},"WG client app")," for your platform (Linux, Windows, MacOS, Android or iOS are all supported)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Create new Client Tunnel")," - On your client app, there should be an option to create a new tunnel, when doing so a client private key will be generated (but if not, use the ",(0,r.yg)("inlineCode",{parentName:"li"},"wg genkey")," command again), and keep it somewhere safe. A public key will also be generated, and this will go in our saver config"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Add Clients to Server Config")," - Head back to your ",(0,r.yg)("inlineCode",{parentName:"li"},"wg0.conf")," file on the server, create a ",(0,r.yg)("inlineCode",{parentName:"li"},"[Peer]")," section, and populate the following info",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"AllowedIPs")," - List of IP address inside the subnet, the client should have access to"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"PublicKey")," - The public key for the client you just generated"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Start the Server")," - You can now start the WG server, using: ",(0,r.yg)("inlineCode",{parentName:"li"},"wg-quick up wg0")," on your server"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Finish Client Setup")," - Head back to your client device, and edit the config file, leave the private key as is, and add the following fields:",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"PublicKey")," - The public key of the server"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Address")," - This should match the ",(0,r.yg)("inlineCode",{parentName:"li"},"AllowedIPs")," section on the servers config file"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"DNS")," - The DNS server that'll be used when accessing the network through the VPN"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"Endpoint")," - The hostname or IP + Port where your WG server is running (you may need to forward this in your firewall's settings)"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Done")," - Your clients should now be able to connect to your WG server :) Depending on your networks firewall rules, you may need to port forward the address of your WG server")),(0,r.yg)("h4",{id:"example-server-config"},(0,r.yg)("strong",{parentName:"h4"},"Example Server Config")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-ini"},"# Server file\n[Interface]\n# Which networks does my interface belong to? Notice: /24 and /64\nAddress = 10.5.0.1/24, 2001:470:xxxx:xxxx::1/64\nPrivateKey = xxx\nListenPort = 51820\n\n# Peer 1\n[Peer]\nPublicKey = xxx\n# Which source IPs can I expect from that peer? Notice: /32 and /128\nAllowedIps = 10.5.0.35/32, 2001:470:xxxx:xxxx::746f:786f/128\n\n# Peer 2\n[Peer]\nPublicKey = xxx\n# Which source IPs can I expect from that peer? This one has a LAN which can\n# access hosts/jails without NAT.\n# Peer 2 has a single IP address inside the VPN: it's 10.5.0.25/32\nAllowedIps = 10.5.0.25/32,10.21.10.0/24,10.21.20.0/24,10.21.30.0/24,10.31.0.0/24,2001:470:xxxx:xxxx::ca:571e/128\n")),(0,r.yg)("h4",{id:"example-client-config"},(0,r.yg)("strong",{parentName:"h4"},"Example Client Config")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-ini"},"[Interface]\n# Which networks does my interface belong to? Notice: /24 and /64\nAddress = 10.5.0.35/24, 2001:470:xxxx:xxxx::746f:786f/64\nPrivateKey = xxx\n\n# Server\n[Peer]\nPublicKey = xxx\n# I want to route everything through the server, both IPv4 and IPv6. All IPs are\n# thus available through the Server, and I can expect packets from any IP to\n# come from that peer.\nAllowedIPs = 0.0.0.0/0, ::0/0\n# Where is the server on the internet? This is a public address. The port\n# (:51820) is the same as ListenPort in the [Interface] of the Server file above\nEndpoint = 1.2.3.4:51820\n# Usually, clients are behind NAT. to keep the connection running, keep alive.\nPersistentKeepalive = 15\n")),(0,r.yg)("p",null,"A useful tool for getting WG setup is ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/trailofbits/algo"},"Algo"),". It includes scripts and docs which cover almost all devices, platforms and clients, and has best practices implemented, and security features enabled. All of this is better explained in ",(0,r.yg)("a",{parentName:"p",href:"https://blog.trailofbits.com/2016/12/12/meet-algo-the-vpn-that-works/"},"this blog post"),"."),(0,r.yg)("h3",{id:"reverse-ssh-tunnel"},"Reverse SSH Tunnel"),(0,r.yg)("p",null,"SSH (or ",(0,r.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Secure_Shell"},"Secure Shell"),") is a secure tunnel that allows you to connect to a remote host. Unlike the VPN methods, an SSH connection does not require an intermediary, and will not be affected by your IP changing. However it only allows you to access a single service at a time. SSH was really designed for terminal access, but because of the latter mentioned benefits it's useful to setup, as a fallback option."),(0,r.yg)("p",null,"Directly SSH'ing into your home, would require you to open a port (usually 22), which would be terrible for security, and is not recommended. However a reverse SSH connection is initiated from inside your network. Once the connection is established, the port is redirected, allowing you to use the established connection to SSH into your home network."),(0,r.yg)("p",null,"The issue you've probably spotted, is that most public, corporate, and institutional networks will block SSH connections. To overcome this, you'd have to establish a server outside of your homelab that your homelab's device could SSH into to establish the reverse SSH connection. You can then connect to that remote server (the ",(0,r.yg)("em",{parentName:"p"},"mothership"),"), which in turn connects to your home network."),(0,r.yg)("p",null,"Now all of this is starting to sound like quite a lot of work, but this is where services like ",(0,r.yg)("a",{parentName:"p",href:"https://remote.it/"},"remot3.it")," come in. They maintain the intermediary mothership server, and create the tunnel service for you. It's free for personal use, secure and easy. There are several similar services, such as ",(0,r.yg)("a",{parentName:"p",href:"https://remoteiot.com/"},"RemoteIoT"),", or you could create your own on a cloud VPS (see ",(0,r.yg)("a",{parentName:"p",href:"https://gist.github.com/nileshtrivedi/4c615e8d3c1bf053b0d31176b9e69e42"},"this tutorial")," for more info on that)."),(0,r.yg)("p",null,"Before getting started, you'll need to head over to ",(0,r.yg)("a",{parentName:"p",href:"https://app.remote.it/auth/#/sign-up"},"Remote.it")," and create an account."),(0,r.yg)("p",null,"Then setup your local device:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"If you haven't already done so, you'll need to enable and configure SSH.",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"This is out-of-scope of this article, but I've explained it in detail in ",(0,r.yg)("a",{parentName:"li",href:"https://notes.aliciasykes.com/22798/my-server-setup#configure-ssh"},"this post"),"."))),(0,r.yg)("li",{parentName:"ol"},"Download the Remote.it install script from their ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/remoteit/installer"},"GitHub"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"curl -LkO https://raw.githubusercontent.com/remoteit/installer/master/scripts/auto-install.sh")))),(0,r.yg)("li",{parentName:"ol"},"Make it executable, with ",(0,r.yg)("inlineCode",{parentName:"li"},"chmod +x ./auto-install.sh"),", and then run it with ",(0,r.yg)("inlineCode",{parentName:"li"},"sudo ./auto-install.sh")),(0,r.yg)("li",{parentName:"ol"},"Finally, configure your device, by running ",(0,r.yg)("inlineCode",{parentName:"li"},"sudo connectd_installer")," and following the on-screen instructions")),(0,r.yg)("p",null,"And when you're ready to connect to it:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Login to ",(0,r.yg)("a",{parentName:"li",href:"https://app.remote.it/"},"app.remote.it"),", and select the name of your device"),(0,r.yg)("li",{parentName:"ol"},"You should see a list of running services, click SSH"),(0,r.yg)("li",{parentName:"ol"},"You'll then be presented with some SSH credentials that you can now use to securely connect to your home, via the Remote.it servers")),(0,r.yg)("p",null,"Done :)"),(0,r.yg)("h3",{id:"tcp-tunnel"},"TCP Tunnel"),(0,r.yg)("p",null,"If you're running Dashy on your local network, behind a firewall, but need to temporarily share it with someone external, this can be achieved quickly and securely using ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/"},"Ngrok"),". It's basically a super slick, encrypted TCP tunnel that provides an internet-accessible address that anyone use to access your local service, from anywhere."),(0,r.yg)("p",null,"To get started, ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/download"},"Download")," and install Ngrok for your system, then just run ",(0,r.yg)("inlineCode",{parentName:"p"},"ngrok http [port]")," (replace the port with the http port where Dashy is running, e.g. 8080). When ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs#http-local-https"},"using https"),", specify the full local url/ ip including the protocol."),(0,r.yg)("p",null,"Some Ngrok features require you to be authenticated, you can ",(0,r.yg)("a",{parentName:"p",href:"https://dashboard.ngrok.com/signup"},"create a free account")," and generate a token in ",(0,r.yg)("a",{parentName:"p",href:"https://dashboard.ngrok.com/auth/your-authtoken"},"your dashboard"),", then run ",(0,r.yg)("inlineCode",{parentName:"p"},"ngrok authtoken [token]"),"."),(0,r.yg)("p",null,"It's recommended to use authentication for any publicly accessible service. Dashy has an ",(0,r.yg)("a",{parentName:"p",href:"/docs/authentication"},"Auth")," feature built in, but an even easier method it to use the ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs#http-auth"},(0,r.yg)("inlineCode",{parentName:"a"},"-auth"))," switch. E.g. ",(0,r.yg)("inlineCode",{parentName:"p"},'ngrok http -auth="username:password123" 8080')),(0,r.yg)("p",null,"By default, your web app is assigned a randomly generated ngrok domain, but you can also use your own custom domain. Under the ",(0,r.yg)("a",{parentName:"p",href:"https://dashboard.ngrok.com/endpoints/domains"},"Domains Tab")," of your Ngrok dashboard, add your domain, and follow the CNAME instructions. You can now use your domain, with the ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs#http-custom-domains"},(0,r.yg)("inlineCode",{parentName:"a"},"-hostname"))," switch, e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"ngrok http -region=us -hostname=dashy.example.com 8080"),". If you don't have your own domain name, you can instead use a custom sub-domain (e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"alicia-dashy.ngrok.io"),"), using the ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs#custom-subdomain-names"},(0,r.yg)("inlineCode",{parentName:"a"},"-subdomain"))," switch."),(0,r.yg)("p",null,"To integrate this into your docker-compose, take a look at the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/gtriggiano/ngrok-tunnel"},"gtriggiano/ngrok-tunnel")," container."),(0,r.yg)("p",null,"There's so much more you can do with Ngrok, such as exposing a directory as a file browser, using websockets, relaying requests, rewriting headers, inspecting traffic, TLS and TCP tunnels and lots more. All or which is explained in ",(0,r.yg)("a",{parentName:"p",href:"https://ngrok.com/docs"},"the Documentation"),"."),(0,r.yg)("p",null,"It's worth noting that Ngrok isn't the only option here, other options include: ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/fatedier/frp"},"FRP"),", ",(0,r.yg)("a",{parentName:"p",href:"https://inlets.dev"},"Inlets"),", ",(0,r.yg)("a",{parentName:"p",href:"https://localtunnel.me/"},"Local Tunnel"),", ",(0,r.yg)("a",{parentName:"p",href:"https://tailscale.com/"},"TailScale"),", etc. Check out ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/anderspitman/awesome-tunneling"},"Awesome Tunneling")," for a list of alternatives."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"custom-domain"},"Custom Domain"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#using-nginx"},"Using DNS")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#using-dns"},"Using NGINX"))),(0,r.yg)("h3",{id:"using-dns"},"Using DNS"),(0,r.yg)("p",null,"For locally running services, a domain can be set up directly in the DNS records. This method is really quick and easy, and doesn't require you to purchase an actual domain. Just update your networks DNS resolver, to point your desired URL to the local IP where Dashy (or any other app) is running. For example, a line in your hosts file might look something like: ",(0,r.yg)("inlineCode",{parentName:"p"},"192.168.0.2 dashy.homelab.local"),"."),(0,r.yg)("p",null,"If you're using Pi-Hole, a similar thing can be done in the ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/dnsmasq.d/03-custom-dns.conf")," file, add a line like: ",(0,r.yg)("inlineCode",{parentName:"p"},"address=/dashy.example.com/192.168.2.0")," for each of your services."),(0,r.yg)("p",null,"If you're running OPNSense/ PfSense, then this can be done through the UI with Unbound, it's explained nicely in ",(0,r.yg)("a",{parentName:"p",href:"https://homenetworkguy.com/how-to/use-custom-domain-name-in-internal-network/"},"this article"),", by Dustin Casto."),(0,r.yg)("h3",{id:"using-nginx"},"Using NGINX"),(0,r.yg)("p",null,"If you're using NGINX, then you can use your own domain name, with a config similar to the below example."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"upstream dashy {\n server 127.0.0.1:32400;\n}\n\nserver {\n listen 80;\n server_name dashy.mydomain.com;\n\n # Setup SSL\n ssl_certificate /var/www/mydomain/sslcert.pem;\n ssl_certificate_key /var/www/mydomain/sslkey.pem;\n ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';\n ssl_session_timeout 5m;\n ssl_prefer_server_ciphers on;\n\n location / {\n proxy_pass http://dashy;\n proxy_redirect off;\n proxy_buffering off;\n proxy_set_header host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;\n }\n}\n")),(0,r.yg)("p",null,"Similarly, a basic ",(0,r.yg)("inlineCode",{parentName:"p"},"Caddyfile")," might look like:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"dashy.example.com {\n reverse_proxy / nginx:80\n}\n")),(0,r.yg)("p",null,"For more info, ",(0,r.yg)("a",{parentName:"p",href:"https://thehomelab.wiki/books/dns-reverse-proxy/page/create-domain-records-to-point-to-your-home-server-on-cloudflare-using-nginx-progy-manager"},"this guide")," on Setting up Domains with NGINX Proxy Manager and CloudFlare may be useful."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"container-security"},"Container Security"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#keep-docker-up-to-date"},"Keep Docker Up-To-Date")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#set-resource-quotas"},"Set Resource Quotas")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#dont-run-as-root"},"Don't Run as Root")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#specify-a-user"},"Specify a User")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#limit-capabilities"},"Limit Capabilities")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#prevent-new-privileges-being-added"},"Prevent new Privileges being Added")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#disable-inter-container-communication"},"Disable Inter-Container Communication")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#dont-expose-the-docker-daemon-socket"},"Don't Expose the Docker Daemon Socket")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#use-read-only-volumes"},"Use Read-Only Volumes")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#set-the-logging-level"},"Set the Logging Level")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#verify-image-before-pulling"},"Verify Image before Pulling")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#specify-the-tag"},"Specify the Tag")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#container-security-scanning"},"Container Security Scanning")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#registry-security"},"Registry Security")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#security-modules"},"Security Modules"))),(0,r.yg)("h3",{id:"keep-docker-up-to-date"},"Keep Docker Up-To-Date"),(0,r.yg)("p",null,"To prevent known container escape vulnerabilities, which typically end in escalating to root/administrator privileges, patching Docker Engine and Docker Machine is crucial. For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/install/"},"Docker Installation Docs"),"."),(0,r.yg)("h3",{id:"set-resource-quotas"},"Set Resource Quotas"),(0,r.yg)("p",null,"Docker enables you to limit resource consumption (CPU, memory, disk) on a per-container basis. This not only enhances system performance, but also prevents a compromised container from consuming a large amount of resources, in order to disrupt service or perform malicious activities. To learn more, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/containers/resource_constraints/"},"Resource Constraints Docs")),(0,r.yg)("p",null,"For example, to run Dashy with max of 1GB ram, and max of 50% of 1 CP core:\n",(0,r.yg)("inlineCode",{parentName:"p"},'docker run -d -p 8080:80 --cpus=".5" --memory="1024m" lissy93/dashy:latest')),(0,r.yg)("h3",{id:"dont-run-as-root"},"Don't Run as Root"),(0,r.yg)("p",null,"Running a container with admin privileges gives it more power than it needs, and can be abused. Dashy does not need any root privileges, and Docker by default doesn't run containers as root, so providing you don't specifically type sudo, you should be all good here."),(0,r.yg)("p",null,"Note that if you're facing permission issues on Debian-based systems, you may need to add your user to the Docker group. First create the group: ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo groupadd docker"),", then add your (non-root) user: ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo usermod \u2212aG docker [my-username]"),", finally ",(0,r.yg)("inlineCode",{parentName:"p"},"newgrp docker")," to refresh."),(0,r.yg)("h3",{id:"specify-a-user"},"Specify a User"),(0,r.yg)("p",null,"One of the best ways to prevent privilege escalation attacks, is to configure the container to use an unprivileged user. This also means that any files created by the container and mounted, will be owned by the specified user (and not root), which makes things much easier."),(0,r.yg)("p",null,"You can specify a user, using the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/run/#user"},(0,r.yg)("inlineCode",{parentName:"a"},"--user")," param"),", and should include the user ID (",(0,r.yg)("inlineCode",{parentName:"p"},"UID"),"), which can be found by running ",(0,r.yg)("inlineCode",{parentName:"p"},"id -u"),", and the and the group ID (",(0,r.yg)("inlineCode",{parentName:"p"},"GID"),"), using ",(0,r.yg)("inlineCode",{parentName:"p"},"id -g"),"."),(0,r.yg)("p",null,"With Docker run, you specify it like:\n",(0,r.yg)("inlineCode",{parentName:"p"},"docker run --user 1000:1000 -p 8080:80 lissy93/dashy")),(0,r.yg)("p",null,"Of if you're using Docker-compose, you could use an environmental variable"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},'version: "3.8"\nservices:\n dashy:\n image: lissy93/dashy\n user: ${CURRENT_UID}\n ports: [ 4000:80 ]\n')),(0,r.yg)("p",null,"And then to set the variable, and start the container, run: ",(0,r.yg)("inlineCode",{parentName:"p"},"CURRENT_UID=$(id -u):$(id -g) docker-compose up")),(0,r.yg)("h3",{id:"limit-capabilities"},"Limit capabilities"),(0,r.yg)("p",null,"Docker containers run with a subset of ",(0,r.yg)("a",{parentName:"p",href:"https://man7.org/linux/man-pages/man7/capabilities.7.html"},"Linux Kernal's Capabilities")," by default. It's good practice to drop privilege permissions that are not needed for any given container."),(0,r.yg)("p",null,"With Docker run, you can use the ",(0,r.yg)("inlineCode",{parentName:"p"},"--cap-drop")," flag to remove capabilities, you can also use ",(0,r.yg)("inlineCode",{parentName:"p"},"--cap-drop=all")," and then define just the required permissions using the ",(0,r.yg)("inlineCode",{parentName:"p"},"--cap-add")," option. For a list of available capabilities, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities"},"Privilege Capabilities Docs"),"."),(0,r.yg)("p",null,"Note that dropping privileges and capabilities on runtime is not fool-proof, and often any leftover privileges can be used to re-escalate, see ",(0,r.yg)("a",{parentName:"p",href:"https://wiki.sei.cmu.edu/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges"},"POS36-C"),"."),(0,r.yg)("p",null,"Here's an example using docker-compose, removing privileges that are not required for Dashy to run:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},'version: "3.8"\nservices:\n dashy:\n image: lissy93/dashy\n ports: [ 4000:80 ]\n cap_drop:\n - ALL\n cap_add:\n - CHOWN\n - SETGID\n - SETUID\n - DAC_OVERRIDE\n - NET_BIND_SERVICE\n')),(0,r.yg)("h3",{id:"prevent-new-privileges-being-added"},"Prevent new Privileges being Added"),(0,r.yg)("p",null,"To prevent processes inside the container from getting additional privileges, pass in the ",(0,r.yg)("inlineCode",{parentName:"p"},"--security-opt=no-new-privileges:true")," option to the Docker run command (see ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/run/#security-configuration"},"docs"),")."),(0,r.yg)("p",null,"Run Command:\n",(0,r.yg)("inlineCode",{parentName:"p"},"docker run --security-opt=no-new-privileges:true -p 8080:80 lissy93/dashy")),(0,r.yg)("p",null,"Docker Compose"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"security_opt:\n- no-new-privileges:true\n")),(0,r.yg)("h3",{id:"disable-inter-container-communication"},"Disable Inter-Container Communication"),(0,r.yg)("p",null,"By default Docker containers can talk to each other (using ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/config/containers/container-networking/"},(0,r.yg)("inlineCode",{parentName:"a"},"docker0")," bridged network"),"). If you don't need this capability, then it should be disabled. This can be done with the ",(0,r.yg)("inlineCode",{parentName:"p"},"--icc=false")," in your run command. You can learn more about how to facilitate secure communication between containers in the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/compose/networking/"},"Compose Networking docs"),"."),(0,r.yg)("h3",{id:"dont-expose-the-docker-daemon-socket"},"Don't Expose the Docker Daemon Socket"),(0,r.yg)("p",null,"Docker socket ",(0,r.yg)("inlineCode",{parentName:"p"},"/var/run/docker.sock")," is the UNIX socket that Docker is listening to. This is the primary entry point for the Docker API. The owner of this socket is root. Giving someone access to it is equivalent to giving unrestricted root access to your host."),(0,r.yg)("p",null,"You should ",(0,r.yg)("strong",{parentName:"p"},"not")," enable TCP Docker daemon socket (",(0,r.yg)("inlineCode",{parentName:"p"},"-H tcp://0.0.0.0:XXX"),"), as doing so exposes un-encrypted and unauthenticated direct access to the Docker daemon, and if the host is connected to the internet, the daemon on your computer can be used by anyone from the public internet- which is bad. If you need TCP, you should ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option"},"see the docs")," to understand how to do this more securely.\nSimilarly, never expose ",(0,r.yg)("inlineCode",{parentName:"p"},"/var/run/docker.sock")," to other containers as a volume, as it can be exploited."),(0,r.yg)("h3",{id:"use-read-only-volumes"},"Use Read-Only Volumes"),(0,r.yg)("p",null,"You can specify that a specific volume should be read-only by appending ",(0,r.yg)("inlineCode",{parentName:"p"},":ro")," to the ",(0,r.yg)("inlineCode",{parentName:"p"},"-v")," switch. For example, while running Dashy, if we want our config to be writable, but keep all other assets protected, we would do:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n -p 8080:80 \\\n -v ~/dashy-conf.yml:/app/public/conf.yml \\\n -v ~/dashy-icons:/app/public/item-icons:ro \\\n -v ~/dashy-theme.scss:/app/src/styles/user-defined-themes.scss:ro \\\n lissy93/dashy:latest\n")),(0,r.yg)("p",null,"You can also prevent a container from writing any changes to volumes on your host's disk, using the ",(0,r.yg)("inlineCode",{parentName:"p"},"--read-only")," flag. Although, for Dashy, you will not be able to write config changes to disk, when edited through the UI with this method. You could make this work, by specifying the config directory as a temp write location, with ",(0,r.yg)("inlineCode",{parentName:"p"},"--tmpfs /app/public/conf.yml")," - but that this will not write the volume back to your host."),(0,r.yg)("h3",{id:"set-the-logging-level"},"Set the Logging Level"),(0,r.yg)("p",null,"Logging is important, as it enables you to review events in the future, and in the case of a compromise this will let get an idea of what may have happened. The default log level is ",(0,r.yg)("inlineCode",{parentName:"p"},"INFO"),", and this is also the recommendation, use ",(0,r.yg)("inlineCode",{parentName:"p"},"--log-level info")," to ensure this is set."),(0,r.yg)("h3",{id:"verify-image-before-pulling"},"Verify Image before Pulling"),(0,r.yg)("p",null,"Only use trusted images, from verified/ official sources. If an app is open source, it is more likely to be safe, as anyone can verify the code. There are also tools available for scanning containers,"),(0,r.yg)("p",null,"Unless otherwise configured, containers can communicate among each other, so running one bad image may lead to other areas of your setup being compromised. Docker images typically contain both original code, as well as up-stream packages, and even if that image has come from a trusted source, the up-stream packages it includes may not have."),(0,r.yg)("h3",{id:"specify-the-tag"},"Specify the Tag"),(0,r.yg)("p",null,"Using fixed tags (as opposed to ",(0,r.yg)("inlineCode",{parentName:"p"},":latest")," ) will ensure immutability, meaning the base image will not change between builds. Note that for Dashy, the app is being actively developed, new features, bug fixes and general improvements are merged each week, and if you use a fixed version you will not enjoy these benefits. So it's up to you weather you would prefer a stable and reproducible environment, or the latest features and enhancements."),(0,r.yg)("h3",{id:"container-security-scanning"},"Container Security Scanning"),(0,r.yg)("p",null,"It's helpful to be aware of any potential security issues in any of the Docker images you are using. You can run a quick scan using Snyk on any image to output known vulnerabilities using ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/scan/"},"Docker scan"),", e.g: ",(0,r.yg)("inlineCode",{parentName:"p"},"docker scan lissy93/dashy:latest"),"."),(0,r.yg)("p",null,"A similar product is ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/aquasecurity/trivy"},"Trivy"),", which is free an open source. First install it (with your package manager), then to scan an image, just run: ",(0,r.yg)("inlineCode",{parentName:"p"},"trivy image lissy93/dashy:latest")),(0,r.yg)("p",null,"For larger systems, RedHat ",(0,r.yg)("a",{parentName:"p",href:"https://www.redhat.com/en/topics/containers/what-is-clair"},"Clair")," is an app for parsing image contents and reporting on any found vulnerabilities. You run it locally in a container, and configure it with YAML. It can be integrated with Red Hat Quay, to show results on a dashboard. Most of these use static analysis to find potential issues, and scan included packages for any known security vulnerabilities."),(0,r.yg)("h3",{id:"registry-security"},"Registry Security"),(0,r.yg)("p",null,"Although over-kill for most users, you could run your own registry locally which would give you ultimate control over all images, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.docker.com/registry/deploying/"},"Deploying a Registry Docs")," for more info. Another option is ",(0,r.yg)("a",{parentName:"p",href:"https://docker-docs.netlify.app/ee/dtr/"},"Docker Trusted Registry"),", it's great for enterprise applications, it sits behind your firewall, running on a swarm managed by Docker Universal Control Plane, and lets you securely store and manage your Docker images, mitigating the risk of breaches from the internet."),(0,r.yg)("h3",{id:"security-modules"},"Security Modules"),(0,r.yg)("p",null,"Docker supports several modules that let you write your own security profiles."),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://www.apparmor.net/"},"AppArmor"),"is a kernel module that proactively protects the operating system and applications from external or internal threats, by enabling you to restrict programs' capabilities with per-program profiles. You can specify either a security policy by name, or by file path with the ",(0,r.yg)("inlineCode",{parentName:"p"},"apparmor")," flag in docker run. Learn more about writing profiles, ",(0,r.yg)("a",{parentName:"p",href:"https://gitlab.com/apparmor/apparmor/-/wikis/QuickProfileLanguage"},"here"),"."),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Seccomp"},"Seccomp")," (Secure Computing Mode) is a sandboxing facility in the Linux kernel that acts like a firewall for system calls (syscalls). It uses Berkeley Packet Filter (BPF) rules to filter syscalls and control how they are handled. These filters can significantly limit a containers access to the Docker Host's Linux kernel - especially for simple containers/applications. It requires a Linux-based Docker host, with secomp enabled, and you can check for this by running ",(0,r.yg)("inlineCode",{parentName:"p"},"docker info | grep seccomp"),". A great resource for learning more about this is ",(0,r.yg)("a",{parentName:"p",href:"https://training.play-with-docker.com/security-seccomp/"},"DockerLabs"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"web-server-configuration"},"Web Server Configuration"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},(0,r.yg)("em",{parentName:"p"},"The following section only applies if you are not using Docker, and would like to use your own web server"))),(0,r.yg)("p",null,"Dashy ships with a pre-configured Node.js server, in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/server.js"},(0,r.yg)("inlineCode",{parentName:"a"},"server.js"))," which serves up the contents of the ",(0,r.yg)("inlineCode",{parentName:"p"},"./dist")," directory on a given port. You can start the server by running ",(0,r.yg)("inlineCode",{parentName:"p"},"node server"),". Note that the app must have been build (run ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn build"),"), and you need ",(0,r.yg)("a",{parentName:"p",href:"https://nodejs.org"},"Node.js")," installed."),(0,r.yg)("p",null,"If you wish to run Dashy from a sub page (e.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"example.com/dashy"),"), then just set the ",(0,r.yg)("inlineCode",{parentName:"p"},"BASE_URL")," environmental variable to that page name (in this example, ",(0,r.yg)("inlineCode",{parentName:"p"},"/dashy"),"), before building the app, and the path to all assets will then resolve to the new path, instead of ",(0,r.yg)("inlineCode",{parentName:"p"},"./"),"."),(0,r.yg)("p",null,"However, since Dashy is just a static web application, it can be served with whatever server you like. The following section outlines how you can configure a web server."),(0,r.yg)("p",null,"Note, that if you choose not to use ",(0,r.yg)("inlineCode",{parentName:"p"},"server.js")," to serve up the app, you will loose access to the following features:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Loading page, while the app is building"),(0,r.yg)("li",{parentName:"ul"},"Writing config file to disk from the UI"),(0,r.yg)("li",{parentName:"ul"},"Website status indicators, and ping checks")),(0,r.yg)("p",null,"Example Configs"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nginx"},"NGINX")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#apache"},"Apache")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#caddy"},"Caddy")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#firebase-hosting"},"Firebase")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpanel"},"cPanel"))),(0,r.yg)("h3",{id:"nginx-1"},"NGINX"),(0,r.yg)("p",null,"Create a new file in ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/nginx/sites-enabled/dashy")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"server {\n listen 80;\n listen [::]:80;\n\n root /var/www/dashy/html;\n index index.html;\n\n server_name your-domain.com www.your-domain.com;\n\n location / {\n try_files $uri $uri/ =404;\n }\n}\n")),(0,r.yg)("p",null,"To use HTML5 history mode (",(0,r.yg)("inlineCode",{parentName:"p"},"appConfig.routingMode: history"),"), replace the inside of the location block with: ",(0,r.yg)("inlineCode",{parentName:"p"},"try_files $uri $uri/ /index.html;"),"."),(0,r.yg)("p",null,"Then upload the build contents of Dashy's dist directory to that location.\nFor example: ",(0,r.yg)("inlineCode",{parentName:"p"},"scp -r ./dist/* [username]@[server_ip]:/var/www/dashy/html")),(0,r.yg)("h3",{id:"apache-1"},"Apache"),(0,r.yg)("p",null,"Copy Dashy's dist folder to your apache server, ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo cp -r ./dashy/dist /var/www/html/dashy"),"."),(0,r.yg)("p",null,"In your Apache config, ",(0,r.yg)("inlineCode",{parentName:"p"},"/etc/apche2/apache2.conf")," add:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"\n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n\n\n\n RewriteEngine On\n RewriteBase /\n RewriteRule ^index\\.html$ - [L]\n RewriteCond %{REQUEST_FILENAME} !-f\n RewriteCond %{REQUEST_FILENAME} !-d\n RewriteRule . /index.html [L]\n\n")),(0,r.yg)("p",null,"Add a ",(0,r.yg)("inlineCode",{parentName:"p"},".htaccess")," file within ",(0,r.yg)("inlineCode",{parentName:"p"},"/var/www/html/dashy/.htaccess"),", and add:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"Options -MultiViews\nRewriteEngine On\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteRule ^ index.html [QSA,L]\n")),(0,r.yg)("p",null,"Then restart Apache, with ",(0,r.yg)("inlineCode",{parentName:"p"},"sudo systemctl restart apache2")),(0,r.yg)("h3",{id:"caddy-1"},"Caddy"),(0,r.yg)("p",null,"Caddy v2"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"try_files {path} /\n")),(0,r.yg)("p",null,"Caddy v1"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"rewrite {\n regexp .*\n to {path} /\n}\n")),(0,r.yg)("h3",{id:"firebase-hosting"},"Firebase Hosting"),(0,r.yg)("p",null,"Create a file names ",(0,r.yg)("inlineCode",{parentName:"p"},"firebase.json"),", and populate it with something similar to:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},'{\n "hosting": {\n "public": "dist",\n "rewrites": [\n {\n "source": "**",\n "destination": "/index.html"\n }\n ]\n }\n}\n')),(0,r.yg)("h3",{id:"cpanel"},"cPanel"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Login to your WHM"),(0,r.yg)("li",{parentName:"ol"},"Open 'Feature Manager' on the left sidebar"),(0,r.yg)("li",{parentName:"ol"},"Under 'Manage feature list', click 'Edit'"),(0,r.yg)("li",{parentName:"ol"},"Find 'Application manager' in the list, enable it and hit 'Save'"),(0,r.yg)("li",{parentName:"ol"},"Log into your users cPanel account, and under 'Software' find 'Application Manager'"),(0,r.yg)("li",{parentName:"ol"},"Click 'Register Application', fill in the form using the path that Dashy is located, and choose a domain, and hit 'Save'"),(0,r.yg)("li",{parentName:"ol"},"The application should now show up in the list, click 'Ensure dependencies', and move the toggle switch to 'Enabled'"),(0,r.yg)("li",{parentName:"ol"},"If you need to change the port, click 'Add environmental variable', give it the name 'PORT', choose a port number and press 'Save'."),(0,r.yg)("li",{parentName:"ol"},"Dashy should now be running at your selected path an on a given port")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"running-a-modified-version-of-the-app"},"Running a Modified Version of the App"),(0,r.yg)("p",null,"If you'd like to make any code changes to the app, and deploy your modified version, this section briefly explains how."),(0,r.yg)("p",null,"The first step is to fork the project on GitHub, and clone it to your local system. Next, install the dependencies (",(0,r.yg)("inlineCode",{parentName:"p"},"yarn"),"), and start the development server (",(0,r.yg)("inlineCode",{parentName:"p"},"yarn dev"),") and visit ",(0,r.yg)("inlineCode",{parentName:"p"},"localhost:8080")," in your browser. You can then make changes to the codebase, and see the live app update in real-time. Once you've finished, running ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn build")," will build the app for production, and output the assets into ",(0,r.yg)("inlineCode",{parentName:"p"},"./dist")," which can then be deployed using a web server, CDN or the built-in Node server with ",(0,r.yg)("inlineCode",{parentName:"p"},"yarn start"),". For more info on all of this, take a look at the ",(0,r.yg)("a",{parentName:"p",href:"/docs/developing"},"Developing Docs"),". To build your own Docker container from the modified app, see ",(0,r.yg)("a",{parentName:"p",href:"#building-your-own-container"},"Building your Own Container")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"building-your-own-container"},"Building your Own Container"),(0,r.yg)("p",null,"Similar to above, you'll first need to fork and clone Dashy to your local system, and then install dependencies."),(0,r.yg)("p",null,"Then, either use Dashy's default ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/Dockerfile"},(0,r.yg)("inlineCode",{parentName:"a"},"Dockerfile"))," as is, or modify it according to your needs."),(0,r.yg)("p",null,"To build and deploy locally, first build the app with: ",(0,r.yg)("inlineCode",{parentName:"p"},"docker build -t dashy ."),", and then start the app with ",(0,r.yg)("inlineCode",{parentName:"p"},"docker run -p 8080:80 --name my-dashboard dashy"),". Or modify the ",(0,r.yg)("inlineCode",{parentName:"p"},"docker-compose.yml")," file, replacing ",(0,r.yg)("inlineCode",{parentName:"p"},"image: lissy93/dashy")," with ",(0,r.yg)("inlineCode",{parentName:"p"},"build: .")," and run ",(0,r.yg)("inlineCode",{parentName:"p"},"docker compose up"),"."),(0,r.yg)("p",null,"Your container should now be running, and will appear in the list when you run ",(0,r.yg)("inlineCode",{parentName:"p"},"docker container ls \u2013a"),". If you'd like to enter the container, run ",(0,r.yg)("inlineCode",{parentName:"p"},"docker exec -it [container-id] /bin/ash"),"."),(0,r.yg)("p",null,"You may wish to upload your image to a container registry for easier access. Note that if you choose to do this on a public registry, please name your container something other than just 'dashy', to avoid confusion with the official image.\nYou can push your build image, by running: ",(0,r.yg)("inlineCode",{parentName:"p"},"docker push ghcr.io/OWNER/IMAGE_NAME:latest"),". You will first need to authenticate, this can be done by running ",(0,r.yg)("inlineCode",{parentName:"p"},"echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin"),", where ",(0,r.yg)("inlineCode",{parentName:"p"},"CR_PAT")," is an environmental variable containing a token generated from your GitHub account. For more info, see the ",(0,r.yg)("a",{parentName:"p",href:"https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry"},"Container Registry Docs"),"."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/27d9d47d.30b89259.js b/assets/js/27d9d47d.30b89259.js new file mode 100644 index 00000000..24aba75c --- /dev/null +++ b/assets/js/27d9d47d.30b89259.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[138],{5680:(e,t,a)=>{a.d(t,{xA:()=>p,yg:()=>c});var r=a(6540);function s(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function n(e){for(var t=1;t=0||(s[a]=e[a]);return s}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(s[a]=e[a])}return s}var l=r.createContext({}),h=function(e){var t=r.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):n(n({},t),e)),a},p=function(e){var t=h(e.components);return r.createElement(l.Provider,{value:t},e.children)},g="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var a=e.components,s=e.mdxType,o=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),g=h(a),u=s,c=g["".concat(l,".").concat(u)]||g[u]||y[u]||o;return a?r.createElement(c,n(n({ref:t},p),{},{components:a})):r.createElement(c,n({ref:t},p))}));function c(e,t){var a=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var o=a.length,n=new Array(o);n[0]=u;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[g]="string"==typeof e?e:s,n[1]=i;for(var h=2;h{a.r(t),a.d(t,{contentTitle:()=>n,default:()=>g,frontMatter:()=>o,metadata:()=>i,toc:()=>l});var r=a(8168),s=(a(6540),a(5680));const o={},n="*Dashy Showcase* \ud83c\udf1f",i={unversionedId:"showcase",id:"showcase",isDocsHomePage:!1,title:"*Dashy Showcase* \ud83c\udf1f",description:"| \ud83d\udc97 Got a sweet dashboard? Submit it to the showcase! \ud83d\udc49 See How |",source:"@site/docs/showcase.md",sourceDirName:".",slug:"/showcase",permalink:"/docs/showcase",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/showcase.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Pages and Sections",permalink:"/docs/pages-and-sections"},next:{title:"Contributing",permalink:"/docs/contributing"}},l=[{value:"MNDashboard",id:"mndashboard",children:[]},{value:"Home Lab 2.0",id:"home-lab-20",children:[]},{value:"Dipan's Dash",id:"dipans-dash",children:[]},{value:"Ratty222",id:"ratty222",children:[]},{value:"Hugalafutro Dashy",id:"hugalafutro-dashy",children:[]},{value:"NAS Home Dashboard",id:"nas-home-dashboard",children:[]},{value:"Brewhack",id:"brewhack",children:[]},{value:"The Dragons Lair",id:"the-dragons-lair",children:[]},{value:"Homelab & VPS dashboard",id:"homelab--vps-dashboard",children:[]},{value:"Raspberry PI Docker Dashboard",id:"raspberry-pi-docker-dashboard",children:[]},{value:"First Week of Self-Hosting",id:"first-week-of-self-hosting",children:[]},{value:"EVO Dashboard",id:"evo-dashboard",children:[]},{value:"The Private Dashboard",id:"the-private-dashboard",children:[]},{value:"Networking Services",id:"networking-services",children:[]},{value:"Dashy Live",id:"dashy-live",children:[]},{value:"System Monitor",id:"system-monitor",children:[]},{value:"Browser Startpage",id:"browser-startpage",children:[]},{value:"CFT Toolbox",id:"cft-toolbox",children:[]},{value:"Bookmarks",id:"bookmarks",children:[]},{value:"Project Management",id:"project-management",children:[]},{value:"Dashy Example",id:"dashy-example",children:[]},{value:"HomeLAb 3.0",id:"homelab-30",children:[]},{value:"Ground Control",id:"ground-control",children:[]},{value:"Croco_Grievous",id:"croco_grievous",children:[]},{value:"Crypto Dash",id:"crypto-dash",children:[]},{value:"Stefantigro",id:"stefantigro",children:[]},{value:"Morning Dashboard",id:"morning-dashboard",children:[]},{value:"Yet Another Homelab",id:"yet-another-homelab",children:[]},{value:"Submitting your Dashboard",id:"submitting-your-dashboard",children:[{value:"How to Submit",id:"how-to-submit",children:[]},{value:"What to Include",id:"what-to-include",children:[]},{value:"Template",id:"template",children:[]}]}],h={toc:l},p="wrapper";function g(e){let{components:t,...a}=e;return(0,s.yg)(p,(0,r.A)({},h,a,{components:t,mdxType:"MDXLayout"}),(0,s.yg)("h1",{id:"dashy-showcase-"},(0,s.yg)("em",{parentName:"h1"},"Dashy Showcase")," \ud83c\udf1f"),(0,s.yg)("table",null,(0,s.yg)("thead",{parentName:"table"},(0,s.yg)("tr",{parentName:"thead"},(0,s.yg)("th",{parentName:"tr",align:null},"\ud83d\udc97 Got a sweet dashboard? Submit it to the showcase! \ud83d\udc49 ",(0,s.yg)("a",{parentName:"th",href:"#submitting-your-dashboard"},"See How"))))),(0,s.yg)("h2",{id:"mndashboard"},"MNDashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/mahrnet"},"@mahrnet")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/1491"},"#1491")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/mCJRZgp/d2-At-QO4c-PT4u.png",alt:"screenshot-MNDashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"home-lab-20"},"Home Lab 2.0"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/1-home-lab-material.png",alt:"screenshot-homelab"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"dipans-dash"},"Dipan's Dash"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/dipanghosh"},"@Dipanghosh")," - ",(0,s.yg)("a",{parentName:"p",href:"https://dipan.de/"},"dipan.de")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions/777"},"#777")))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"With the option of embedding iframes, it becomes possible to combine and conquer. I have set up Dashy to include graphs from grafana, and set them so that they update automatically. I also have uptime monitors from uptime Kuma, panels from homeassistant are also possible to be included.",(0,s.yg)("br",null),"\nDashy is awesome!")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/bPC6w2n/dipanghosh-dashboard.png",alt:"screenshot-dipanghosh-dashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"ratty222"},"Ratty222"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/ratty222"},"@ratty222")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions/384"},"#384")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/1862727/147582551-4c655d37-8bcc-4f95-ab41-164a9d0d6a07.png",alt:"screenshot-ratty222-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"hugalafutro-dashy"},"Hugalafutro Dashy"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/hugalafutro"},"@hugalafutro")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions/505"},"#505")))),(0,s.yg)("p",null,(0,s.yg)("a",{parentName:"p",href:"https://i.ibb.co/PDpLDKS/hugalafutro-dashy.gif"},(0,s.yg)("img",{parentName:"a",src:"https://i.ibb.co/PDpLDKS/hugalafutro-dashy.gif",alt:"hugalafutro-dashy-screenshot"}))),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"nas-home-dashboard"},"NAS Home Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/cerealconyogurt"},"@cerealconyogurt")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/74"},"#74")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/6-nas-home-dashboard.png",alt:"screenshot-networking-services"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"brewhack"},"Brewhack"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/brpeterso"},"@brpeterso")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/680"},"#680")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/cNjzPT4/brewhack.png",alt:"screenshot-brewhack-dashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"the-dragons-lair"},"The Dragons Lair"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/dr460nf1r3"},"dr460nf1r3")," ",(0,s.yg)("sup",null,"via ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/684"},"#684")))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"My new startpage featuring the stuff I use most. And of course dragons!")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/13-dragons-lair.png",alt:"screenshot-dragons-lair"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"homelab--vps-dashboard"},"Homelab & VPS dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/shadowking001"},"@shadowking001")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/86"},"#86")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/8-shadowking001s-dashy.png",alt:"screenshot-shadowking001-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"raspberry-pi-docker-dashboard"},"Raspberry PI Docker Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/henkiewie"},"@henkiewie")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/622"},"#622")))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"I use this dashboard every day. It now even includes a player for a radio stream which I configured with Logitech media server and icecast. I made an smaller version of the grafana dashboard to fit an iframe in kiosk mode, so it monitors the most important values of my RPI. The PI is in Argon m2 case and used as a NAS. The dashboard is a copy of the adventure theme with some changes saved in ",(0,s.yg)("inlineCode",{parentName:"p"},"/app/src/styles/user-defined-themes.scss"))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/jGzPm6b/henkiewie-dashy-showcase.png",alt:"screenshot-henkiewie-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"first-week-of-self-hosting"},"First Week of Self-Hosting"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/user/RickyCZ"},"u//RickyCZ")," ",(0,s.yg)("sup",null,"via ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/r/selfhosted/comments/pose15/just_got_started_a_week_ago_selfhosting_is_very/"},"Reddit")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/11-ricky-cz.png",alt:"screenshot-week-of-self-hosting"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"evo-dashboard"},"EVO Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/EVOTk"},"@EVOTk")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/pull/316"},"#316")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/12-evo-dashboard.png",alt:"screenshot-evo-dashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"the-private-dashboard"},"The Private Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/DylanBeMe"},"@DylanBeMe")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/419"},"#419")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/hKS483T/private-dashboard-Dylan-Be-Me.png",alt:"screenshot-private-dashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"networking-services"},"Networking Services"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/lissy93"},"@Lissy93"))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/2-networking-services-minimal-dark.png",alt:"screenshot-networking-services"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"dashy-live"},"Dashy Live"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/lissy93"},"@Lissy93"))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"A dashboard I made to manage all project development links from one place. View demo at ",(0,s.yg)("a",{parentName:"p",href:"https://live.dashy.to/"},"live.dashy.to"),".")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/10-dashy-live.png",alt:"screenshot-dashy-live"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"system-monitor"},"System Monitor"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"An aggregated board for monitoring system resource usage from a single view")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/xfK6BGb/system-monitor-board.png",alt:"screenshot-monitor"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"browser-startpage"},"Browser Startpage"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/rs07dS1/startpage.png",alt:"screenshot-startpage"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"cft-toolbox"},"CFT Toolbox"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/3-cft-toolbox.png",alt:"screenshot-cft-toolbox"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"bookmarks"},"Bookmarks"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/4-bookmarks-colourful.png",alt:"screenshot-bookmarks"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"project-management"},"Project Management"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/5-project-management.png",alt:"screenshot-project-management"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"dashy-example"},"Dashy Example"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"An example dashboard, by ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/lissy93"},"@Lissy93"),". View live at ",(0,s.yg)("a",{parentName:"p",href:"https://demo.dashy.to/"},"demo.dashy.to"),".")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/YbzqPK7/demo-dashy.png",alt:"screenshot-dashy-example"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"homelab-30"},"HomeLAb 3.0"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/skoogee"},"@skoogee")," (",(0,s.yg)("a",{parentName:"p",href:"http://zhrn.cc"},"http://zhrn.cc"),") ",(0,s.yg)("sup",null,(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/279"},"#279")))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"Dashy, is the most complete dashboard I ever tried, has all the features, and it sets itself apart from the rest. It is my default homepage now. I am thankful to the developer @Lissy93 for sharing such a wonderful creation.")),(0,s.yg)("p",null,(0,s.yg)("a",{parentName:"p",href:"https://ibb.co/album/ynSwzm"},(0,s.yg)("img",{parentName:"a",src:"https://i.ibb.co/F5yBTsT/12-skoogee-homelab-3.png?",alt:"screenshot-12-skoogee-homelab-3"}))),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"ground-control"},"Ground Control"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/dtctek"},"@dtctek")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/83"},"#83")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/1862727/149821995-e9b41dab-186c-42e6-b5b3-e233259b241d.png",alt:"screenshot-ground-control"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"croco_grievous"},"Croco_Grievous"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/user/Croco_Grievous/"},"u/Croco_Grievous")," ",(0,s.yg)("sup",null,"via ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/r/selfhosted/comments/t4xk3z/everything_started_with_pihole_on_a_raspberry_pi/"},"reddit")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/59XR8KL/dashy-Croco-Grievous.png",alt:"screenshot-croco-grievous-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"crypto-dash"},"Crypto Dash"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"Example usage of widgets to monitor cryptocurrencies news, prices and data. Config is ",(0,s.yg)("a",{parentName:"p",href:"https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10#file-example-8-dashy-crypto-widgets-conf-yml"},"available here"))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/1862727/147394584-352fe3bf-740d-4624-a01b-9003a97bc832.png",alt:"screenshot-crypto-dash"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"stefantigro"},"Stefantigro"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/user/stefantigro/"},"u/stefantigro")," ",(0,s.yg)("sup",null,"via ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/r/selfhosted/comments/t5oril/been_selfhosting_close_to_half_a_year_now_all/"},"reddit")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/1Kb43Yy/dashy-stefantigro.png",alt:"screenshot-stefantigro-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"morning-dashboard"},"Morning Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"Displayed on my smart screen between 05:00 - 08:00, and includes all the info that I usually check before leaving for work")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/4Wx8zb7/morning-dashboard.png",alt:"screenshot-morning-dash"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"yet-another-homelab"},"Yet Another Homelab"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/9-home-lab-oblivion.png",alt:"screenshot-yet-another-homelab"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"submitting-your-dashboard"},"Submitting your Dashboard"),(0,s.yg)("h3",{id:"how-to-submit"},"How to Submit"),(0,s.yg)("ul",null,(0,s.yg)("li",{parentName:"ul"},(0,s.yg)("a",{parentName:"li",href:"https://git.io/JEtgM"},"Open an Issue")),(0,s.yg)("li",{parentName:"ul"},(0,s.yg)("a",{parentName:"li",href:"https://github.com/Lissy93/dashy/compare"},"Open a PR"))),(0,s.yg)("h3",{id:"what-to-include"},"What to Include"),(0,s.yg)("p",null,"Please include the following information:"),(0,s.yg)("ul",null,(0,s.yg)("li",{parentName:"ul"},"A single high-quality screenshot of your Dashboard"),(0,s.yg)("li",{parentName:"ul"},"A short title (it doesn't have to be particularly imaginative)"),(0,s.yg)("li",{parentName:"ul"},"An optional description, you could include details on anything interesting or unique about your dashboard, or say how you use it, and why it's awesome"),(0,s.yg)("li",{parentName:"ul"},"Optionally leave your name or username, with a link to your GitHub, Twitter or Website")),(0,s.yg)("h3",{id:"template"},"Template"),(0,s.yg)("p",null,"If you're submitting a pull request, please use a format similar to this:"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-text"},"### [Dashboard Name] (required)\n\n> Submitted by [@username](https://github.com/user) (optional)\n\n[An optional text description, or any interesting details] (optional)\n\n![dashboard-screenshot](https://example.com/url-to-screenshot.png) (required)\n\n---\n\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/27d9d47d.f584d6da.js b/assets/js/27d9d47d.f584d6da.js deleted file mode 100644 index eb21c23a..00000000 --- a/assets/js/27d9d47d.f584d6da.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[138],{5680:(e,t,a)=>{a.d(t,{xA:()=>p,yg:()=>c});var r=a(6540);function s(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function n(e){for(var t=1;t=0||(s[a]=e[a]);return s}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(s[a]=e[a])}return s}var l=r.createContext({}),h=function(e){var t=r.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):n(n({},t),e)),a},p=function(e){var t=h(e.components);return r.createElement(l.Provider,{value:t},e.children)},g="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var a=e.components,s=e.mdxType,o=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),g=h(a),u=s,c=g["".concat(l,".").concat(u)]||g[u]||y[u]||o;return a?r.createElement(c,n(n({ref:t},p),{},{components:a})):r.createElement(c,n({ref:t},p))}));function c(e,t){var a=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var o=a.length,n=new Array(o);n[0]=u;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[g]="string"==typeof e?e:s,n[1]=i;for(var h=2;h{a.r(t),a.d(t,{contentTitle:()=>n,default:()=>g,frontMatter:()=>o,metadata:()=>i,toc:()=>l});var r=a(8168),s=(a(6540),a(5680));const o={},n="*Dashy Showcase* \ud83c\udf1f",i={unversionedId:"showcase",id:"showcase",isDocsHomePage:!1,title:"*Dashy Showcase* \ud83c\udf1f",description:"| \ud83d\udc97 Got a sweet dashboard? Submit it to the showcase! \ud83d\udc49 See How |",source:"@site/docs/showcase.md",sourceDirName:".",slug:"/showcase",permalink:"/docs/showcase",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/showcase.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Pages and Sections",permalink:"/docs/pages-and-sections"},next:{title:"Contributing",permalink:"/docs/contributing"}},l=[{value:"Home Lab 2.0",id:"home-lab-20",children:[]},{value:"Dipan's Dash",id:"dipans-dash",children:[]},{value:"Ratty222",id:"ratty222",children:[]},{value:"Hugalafutro Dashy",id:"hugalafutro-dashy",children:[]},{value:"NAS Home Dashboard",id:"nas-home-dashboard",children:[]},{value:"Brewhack",id:"brewhack",children:[]},{value:"The Dragons Lair",id:"the-dragons-lair",children:[]},{value:"Homelab & VPS dashboard",id:"homelab--vps-dashboard",children:[]},{value:"Raspberry PI Docker Dashboard",id:"raspberry-pi-docker-dashboard",children:[]},{value:"First Week of Self-Hosting",id:"first-week-of-self-hosting",children:[]},{value:"EVO Dashboard",id:"evo-dashboard",children:[]},{value:"The Private Dashboard",id:"the-private-dashboard",children:[]},{value:"Networking Services",id:"networking-services",children:[]},{value:"Dashy Live",id:"dashy-live",children:[]},{value:"System Monitor",id:"system-monitor",children:[]},{value:"Browser Startpage",id:"browser-startpage",children:[]},{value:"CFT Toolbox",id:"cft-toolbox",children:[]},{value:"Bookmarks",id:"bookmarks",children:[]},{value:"Project Management",id:"project-management",children:[]},{value:"Dashy Example",id:"dashy-example",children:[]},{value:"HomeLAb 3.0",id:"homelab-30",children:[]},{value:"Ground Control",id:"ground-control",children:[]},{value:"Croco_Grievous",id:"croco_grievous",children:[]},{value:"Crypto Dash",id:"crypto-dash",children:[]},{value:"Stefantigro",id:"stefantigro",children:[]},{value:"Morning Dashboard",id:"morning-dashboard",children:[]},{value:"Yet Another Homelab",id:"yet-another-homelab",children:[]},{value:"Submitting your Dashboard",id:"submitting-your-dashboard",children:[{value:"How to Submit",id:"how-to-submit",children:[]},{value:"What to Include",id:"what-to-include",children:[]},{value:"Template",id:"template",children:[]}]}],h={toc:l},p="wrapper";function g(e){let{components:t,...a}=e;return(0,s.yg)(p,(0,r.A)({},h,a,{components:t,mdxType:"MDXLayout"}),(0,s.yg)("h1",{id:"dashy-showcase-"},(0,s.yg)("em",{parentName:"h1"},"Dashy Showcase")," \ud83c\udf1f"),(0,s.yg)("table",null,(0,s.yg)("thead",{parentName:"table"},(0,s.yg)("tr",{parentName:"thead"},(0,s.yg)("th",{parentName:"tr",align:null},"\ud83d\udc97 Got a sweet dashboard? Submit it to the showcase! \ud83d\udc49 ",(0,s.yg)("a",{parentName:"th",href:"#submitting-your-dashboard"},"See How"))))),(0,s.yg)("h2",{id:"home-lab-20"},"Home Lab 2.0"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/1-home-lab-material.png",alt:"screenshot-homelab"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"dipans-dash"},"Dipan's Dash"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/dipanghosh"},"@Dipanghosh")," - ",(0,s.yg)("a",{parentName:"p",href:"https://dipan.de/"},"dipan.de")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions/777"},"#777")))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"With the option of embedding iframes, it becomes possible to combine and conquer. I have set up Dashy to include graphs from grafana, and set them so that they update automatically. I also have uptime monitors from uptime Kuma, panels from homeassistant are also possible to be included.",(0,s.yg)("br",null),"\nDashy is awesome!")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/bPC6w2n/dipanghosh-dashboard.png",alt:"screenshot-dipanghosh-dashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"ratty222"},"Ratty222"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/ratty222"},"@ratty222")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions/384"},"#384")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/1862727/147582551-4c655d37-8bcc-4f95-ab41-164a9d0d6a07.png",alt:"screenshot-ratty222-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"hugalafutro-dashy"},"Hugalafutro Dashy"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/hugalafutro"},"@hugalafutro")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions/505"},"#505")))),(0,s.yg)("p",null,(0,s.yg)("a",{parentName:"p",href:"https://i.ibb.co/PDpLDKS/hugalafutro-dashy.gif"},(0,s.yg)("img",{parentName:"a",src:"https://i.ibb.co/PDpLDKS/hugalafutro-dashy.gif",alt:"hugalafutro-dashy-screenshot"}))),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"nas-home-dashboard"},"NAS Home Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/cerealconyogurt"},"@cerealconyogurt")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/74"},"#74")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/6-nas-home-dashboard.png",alt:"screenshot-networking-services"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"brewhack"},"Brewhack"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/brpeterso"},"@brpeterso")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/680"},"#680")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/cNjzPT4/brewhack.png",alt:"screenshot-brewhack-dashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"the-dragons-lair"},"The Dragons Lair"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/dr460nf1r3"},"dr460nf1r3")," ",(0,s.yg)("sup",null,"via ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/684"},"#684")))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"My new startpage featuring the stuff I use most. And of course dragons!")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/13-dragons-lair.png",alt:"screenshot-dragons-lair"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"homelab--vps-dashboard"},"Homelab & VPS dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/shadowking001"},"@shadowking001")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/86"},"#86")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/8-shadowking001s-dashy.png",alt:"screenshot-shadowking001-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"raspberry-pi-docker-dashboard"},"Raspberry PI Docker Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/henkiewie"},"@henkiewie")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/622"},"#622")))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"I use this dashboard every day. It now even includes a player for a radio stream which I configured with Logitech media server and icecast. I made an smaller version of the grafana dashboard to fit an iframe in kiosk mode, so it monitors the most important values of my RPI. The PI is in Argon m2 case and used as a NAS. The dashboard is a copy of the adventure theme with some changes saved in ",(0,s.yg)("inlineCode",{parentName:"p"},"/app/src/styles/user-defined-themes.scss"))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/jGzPm6b/henkiewie-dashy-showcase.png",alt:"screenshot-henkiewie-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"first-week-of-self-hosting"},"First Week of Self-Hosting"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/user/RickyCZ"},"u//RickyCZ")," ",(0,s.yg)("sup",null,"via ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/r/selfhosted/comments/pose15/just_got_started_a_week_ago_selfhosting_is_very/"},"Reddit")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/11-ricky-cz.png",alt:"screenshot-week-of-self-hosting"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"evo-dashboard"},"EVO Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/EVOTk"},"@EVOTk")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/pull/316"},"#316")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/12-evo-dashboard.png",alt:"screenshot-evo-dashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"the-private-dashboard"},"The Private Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/DylanBeMe"},"@DylanBeMe")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/419"},"#419")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/hKS483T/private-dashboard-Dylan-Be-Me.png",alt:"screenshot-private-dashboard"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"networking-services"},"Networking Services"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/lissy93"},"@Lissy93"))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/2-networking-services-minimal-dark.png",alt:"screenshot-networking-services"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"dashy-live"},"Dashy Live"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/lissy93"},"@Lissy93"))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"A dashboard I made to manage all project development links from one place. View demo at ",(0,s.yg)("a",{parentName:"p",href:"https://live.dashy.to/"},"live.dashy.to"),".")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/10-dashy-live.png",alt:"screenshot-dashy-live"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"system-monitor"},"System Monitor"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"An aggregated board for monitoring system resource usage from a single view")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/xfK6BGb/system-monitor-board.png",alt:"screenshot-monitor"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"browser-startpage"},"Browser Startpage"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/rs07dS1/startpage.png",alt:"screenshot-startpage"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"cft-toolbox"},"CFT Toolbox"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/3-cft-toolbox.png",alt:"screenshot-cft-toolbox"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"bookmarks"},"Bookmarks"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/4-bookmarks-colourful.png",alt:"screenshot-bookmarks"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"project-management"},"Project Management"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/5-project-management.png",alt:"screenshot-project-management"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"dashy-example"},"Dashy Example"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"An example dashboard, by ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/lissy93"},"@Lissy93"),". View live at ",(0,s.yg)("a",{parentName:"p",href:"https://demo.dashy.to/"},"demo.dashy.to"),".")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/YbzqPK7/demo-dashy.png",alt:"screenshot-dashy-example"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"homelab-30"},"HomeLAb 3.0"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/skoogee"},"@skoogee")," (",(0,s.yg)("a",{parentName:"p",href:"http://zhrn.cc"},"http://zhrn.cc"),") ",(0,s.yg)("sup",null,(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/279"},"#279")))),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"Dashy, is the most complete dashboard I ever tried, has all the features, and it sets itself apart from the rest. It is my default homepage now. I am thankful to the developer @Lissy93 for sharing such a wonderful creation.")),(0,s.yg)("p",null,(0,s.yg)("a",{parentName:"p",href:"https://ibb.co/album/ynSwzm"},(0,s.yg)("img",{parentName:"a",src:"https://i.ibb.co/F5yBTsT/12-skoogee-homelab-3.png?",alt:"screenshot-12-skoogee-homelab-3"}))),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"ground-control"},"Ground Control"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/dtctek"},"@dtctek")," ",(0,s.yg)("sup",null,"Re: ",(0,s.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/83"},"#83")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/1862727/149821995-e9b41dab-186c-42e6-b5b3-e233259b241d.png",alt:"screenshot-ground-control"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"croco_grievous"},"Croco_Grievous"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/user/Croco_Grievous/"},"u/Croco_Grievous")," ",(0,s.yg)("sup",null,"via ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/r/selfhosted/comments/t4xk3z/everything_started_with_pihole_on_a_raspberry_pi/"},"reddit")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/59XR8KL/dashy-Croco-Grievous.png",alt:"screenshot-croco-grievous-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"crypto-dash"},"Crypto Dash"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"Example usage of widgets to monitor cryptocurrencies news, prices and data. Config is ",(0,s.yg)("a",{parentName:"p",href:"https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10#file-example-8-dashy-crypto-widgets-conf-yml"},"available here"))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/1862727/147394584-352fe3bf-740d-4624-a01b-9003a97bc832.png",alt:"screenshot-crypto-dash"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"stefantigro"},"Stefantigro"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"By ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/user/stefantigro/"},"u/stefantigro")," ",(0,s.yg)("sup",null,"via ",(0,s.yg)("a",{parentName:"p",href:"https://www.reddit.com/r/selfhosted/comments/t5oril/been_selfhosting_close_to_half_a_year_now_all/"},"reddit")))),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/1Kb43Yy/dashy-stefantigro.png",alt:"screenshot-stefantigro-dashy"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"morning-dashboard"},"Morning Dashboard"),(0,s.yg)("blockquote",null,(0,s.yg)("p",{parentName:"blockquote"},"Displayed on my smart screen between 05:00 - 08:00, and includes all the info that I usually check before leaving for work")),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://i.ibb.co/4Wx8zb7/morning-dashboard.png",alt:"screenshot-morning-dash"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"yet-another-homelab"},"Yet Another Homelab"),(0,s.yg)("p",null,(0,s.yg)("img",{parentName:"p",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/9-home-lab-oblivion.png",alt:"screenshot-yet-another-homelab"})),(0,s.yg)("hr",null),(0,s.yg)("h2",{id:"submitting-your-dashboard"},"Submitting your Dashboard"),(0,s.yg)("h3",{id:"how-to-submit"},"How to Submit"),(0,s.yg)("ul",null,(0,s.yg)("li",{parentName:"ul"},(0,s.yg)("a",{parentName:"li",href:"https://git.io/JEtgM"},"Open an Issue")),(0,s.yg)("li",{parentName:"ul"},(0,s.yg)("a",{parentName:"li",href:"https://github.com/Lissy93/dashy/compare"},"Open a PR"))),(0,s.yg)("h3",{id:"what-to-include"},"What to Include"),(0,s.yg)("p",null,"Please include the following information:"),(0,s.yg)("ul",null,(0,s.yg)("li",{parentName:"ul"},"A single high-quality screenshot of your Dashboard"),(0,s.yg)("li",{parentName:"ul"},"A short title (it doesn't have to be particularly imaginative)"),(0,s.yg)("li",{parentName:"ul"},"An optional description, you could include details on anything interesting or unique about your dashboard, or say how you use it, and why it's awesome"),(0,s.yg)("li",{parentName:"ul"},"Optionally leave your name or username, with a link to your GitHub, Twitter or Website")),(0,s.yg)("h3",{id:"template"},"Template"),(0,s.yg)("p",null,"If you're submitting a pull request, please use a format similar to this:"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-text"},"### [Dashboard Name] (required)\n\n> Submitted by [@username](https://github.com/user) (optional)\n\n[An optional text description, or any interesting details] (optional)\n\n![dashboard-screenshot](https://example.com/url-to-screenshot.png) (required)\n\n---\n\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4bdb0d83.1cbee4f4.js b/assets/js/4bdb0d83.1cbee4f4.js deleted file mode 100644 index 476b529c..00000000 --- a/assets/js/4bdb0d83.1cbee4f4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[496],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>N});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=a.createContext({}),d=function(e){var t=a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(o.Provider,{value:t},e.children)},y="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},s=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,p=g(e,["components","mdxType","originalType","parentName"]),y=d(n),s=r,N=y["".concat(o,".").concat(s)]||y[s]||m[s]||i;return n?a.createElement(N,l(l({ref:t},p),{},{components:n})):a.createElement(N,l({ref:t},p))}));function N(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=s;var g={};for(var o in t)hasOwnProperty.call(t,o)&&(g[o]=t[o]);g.originalType=e,g[y]="string"==typeof e?e:r,l[1]=g;for(var d=2;d{n.r(t),n.d(t,{contentTitle:()=>l,default:()=>y,frontMatter:()=>i,metadata:()=>g,toc:()=>o});var a=n(8168),r=(n(6540),n(5680));const i={},l="Configuring",g={unversionedId:"configuring",id:"configuring",isDocsHomePage:!1,title:"Configuring",description:"All app configuration is specified in /public/conf.yml which is in YAML Format format. If you're using Docker, this file can be passed in as a volume. Changes can either be made directly to this file, or done through the UI. From the UI you can also export, backup, reset, validate and download your configuration file.",source:"@site/docs/configuring.md",sourceDirName:".",slug:"/configuring",permalink:"/docs/configuring",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/configuring.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Deployment",permalink:"/docs/deployment"},next:{title:"App Management",permalink:"/docs/management"}},o=[{value:"There are three ways to edit the config",id:"there-are-three-ways-to-edit-the-config",children:[]},{value:"Tips",id:"tips",children:[]},{value:"Contents",id:"contents",children:[]},{value:"Top-Level Fields",id:"top-level-fields",children:[]},{value:"PageInfo",id:"pageinfo",children:[]},{value:"pageInfo.navLinks (optional)",id:"pageinfonavlinks-optional",children:[]},{value:"pages[] (optional)",id:"pages-optional",children:[]},{value:"appConfig (optional)",id:"appconfig-optional",children:[]},{value:"appConfig.auth (optional)",id:"appconfigauth-optional",children:[]},{value:"appConfig.auth.users (optional)",id:"appconfigauthusers-optional",children:[]},{value:"appConfig.auth.keycloak (optional)",id:"appconfigauthkeycloak-optional",children:[]},{value:"appConfig.webSearch (optional)",id:"appconfigwebsearch-optional",children:[]},{value:"appConfig.hideComponents (optional)",id:"appconfighidecomponents-optional",children:[]},{value:"section",id:"section",children:[]},{value:"section.item",id:"sectionitem",children:[]},{value:"item.displayData (optional)",id:"itemdisplaydata-optional",children:[]},{value:"section.widgets (optional)",id:"sectionwidgets-optional",children:[]},{value:"section.displayData (optional)",id:"sectiondisplaydata-optional",children:[]},{value:"section.icon and section.item.icon",id:"sectionicon-and-sectionitemicon",children:[]},{value:"section.displayData.hideForKeycloakUsers, section.displayData.showForKeycloakUsers, item.displayData.hideForKeycloakUsers and item.displayData.showForKeycloakUsers",id:"sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers",children:[]},{value:"Notes",id:"notes",children:[{value:"Editing Config through the UI",id:"editing-config-through-the-ui",children:[]},{value:"About YAML",id:"about-yaml",children:[]},{value:"Config Saving Methods",id:"config-saving-methods",children:[]},{value:"Preventing Changes",id:"preventing-changes",children:[]},{value:"Example",id:"example",children:[]}]}],d={toc:o},p="wrapper";function y(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,a.A)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"configuring"},"Configuring"),(0,r.yg)("p",null,"All app configuration is specified in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/public/conf.yml"},(0,r.yg)("inlineCode",{parentName:"a"},"/public/conf.yml"))," which is in ",(0,r.yg)("a",{parentName:"p",href:"https://yaml.org/"},"YAML Format")," format. If you're using Docker, this file can be passed in as a volume. Changes can either be made directly to this file, or done ",(0,r.yg)("a",{parentName:"p",href:"#editing-config-through-the-ui"},"through the UI"),". From the UI you can also export, backup, reset, validate and download your configuration file."),(0,r.yg)("h2",{id:"there-are-three-ways-to-edit-the-config"},"There are three ways to edit the config"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Directly in the YAML file")," ",(0,r.yg)("em",{parentName:"li"},"(5/5 reliability, 3/5 usability)"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Write changes directly to the conf.yml file, optionally using one of the templates provided. This can be done in your favorite editor and uploading to your server, or directly editing the file via SSH, but the easiest method would be to use ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/coder/code-server"},"Code Server")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"UI JSON Editor")," ",(0,r.yg)("em",{parentName:"li"},"(4/5 reliability, 4/5 usability)"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"From the UI, under the config menu there is a JSON editor, with built-in validation, documentation and advanced options"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"UI Visual Editor")," ",(0,r.yg)("em",{parentName:"li"},"(3/5 reliability, 5/5 usability)"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"From the UI, enter the Interactive Edit Mode, then click any part of the page to edit. Changes are previewed live, and then saved to disk"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"REST API")," ",(0,r.yg)("em",{parentName:"li"},"(Coming soon)"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Programmatically edit config either through the command line, using a script or a third-party application")))),(0,r.yg)("h2",{id:"tips"},"Tips"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"You may find it helpful to look at some sample config files to get you started, a collection of which can be found ",(0,r.yg)("a",{parentName:"li",href:"https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10"},"here")),(0,r.yg)("li",{parentName:"ul"},"You can check that your config file fits the schema, by running ",(0,r.yg)("inlineCode",{parentName:"li"},"yarn validate-config")),(0,r.yg)("li",{parentName:"ul"},"After modifying your config, the app needs to be recompiled, by running ",(0,r.yg)("inlineCode",{parentName:"li"},"yarn build")," - this happens automatically if you're using Docker"),(0,r.yg)("li",{parentName:"ul"},"It is recommended to keep a backup of your config file. You can download it under Config menu, or use the ",(0,r.yg)("a",{parentName:"li",href:"/docs/backup-restore"},"Cloud Backup")," feature."),(0,r.yg)("li",{parentName:"ul"},"You can make use of YAML features, like anchors, comments, multi-line strings, etc to reuse attributes and keep your config file readable"),(0,r.yg)("li",{parentName:"ul"},"Once you have finished configuring your dashboard, you can choose to ",(0,r.yg)("a",{parentName:"li",href:"#preventing-changes"},"disable UI config")," if you wish"),(0,r.yg)("li",{parentName:"ul"},"All fields are optional, unless otherwise stated.")),(0,r.yg)("p",null,"The following file provides a reference of all supported configuration options."),(0,r.yg)("h2",{id:"contents"},"Contents"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pageinfo"},(0,r.yg)("strong",{parentName:"a"},(0,r.yg)("inlineCode",{parentName:"strong"},"pageInfo")))," - Header text, footer, title, navigation, etc",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pageinfonavlinks-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"navLinks"))," - Links to display in the navigation bar"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pages-optional"},(0,r.yg)("strong",{parentName:"a"},(0,r.yg)("inlineCode",{parentName:"strong"},"pages")))," - List of additional config files, for multi-page dashboards"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfig-optional"},(0,r.yg)("strong",{parentName:"a"},(0,r.yg)("inlineCode",{parentName:"strong"},"appConfig")))," - Main application settings",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfigwebsearch-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"webSearch"))," - Configure web search engine options"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfighidecomponents-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"hideComponents"))," - Show/ hide page components"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfigauth-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"auth"))," - Built-in authentication setup",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfigauthusers-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"users"))," - List or users (for simple auth)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfigauthkeycloak-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"keycloak"))," - Auth config for Keycloak"))))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#section"},(0,r.yg)("strong",{parentName:"a"},(0,r.yg)("inlineCode",{parentName:"strong"},"sections")))," - List of sections",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectiondisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"displayData"))," - Section display settings",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers"},(0,r.yg)("inlineCode",{parentName:"a"},"show/hideForKeycloakUsers"))," - Set user controls"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"a"},"icon"))," - Icon for a section"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectionitem"},(0,r.yg)("inlineCode",{parentName:"a"},"items"))," - List of items",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"a"},"icon"))," - Icon for an item"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#itemdisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"displayData"))," - Item display settings",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers"},(0,r.yg)("inlineCode",{parentName:"a"},"show/hideForKeycloakUsers"))," - Set user controls"))))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectionwidget-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"widgets"))," - List of widgets"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#notes"},(0,r.yg)("strong",{parentName:"a"},"Notes")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#editing-config-through-the-ui"},"Editing Config through the UI")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#about-yaml"},"About YAML")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#config-saving-methods"},"Config Saving Methods")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#preventing-changes"},"Preventing Changes")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#example"},"Example"))))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"top-level-fields"},"Top-Level Fields"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"pageInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Basic meta data like title, description, nav bar links, footer text. See ",(0,r.yg)("a",{parentName:"td",href:"#pageinfo"},(0,r.yg)("inlineCode",{parentName:"a"},"pageInfo")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"appConfig"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Settings related to how the app functions, including API keys and global styles. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfig-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"appConfig")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sections"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"An array of sections, each containing an array of items, which will be displayed as links. See ",(0,r.yg)("a",{parentName:"td",href:"#section"},(0,r.yg)("inlineCode",{parentName:"a"},"section")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"pages"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array additional config files, used for multi-page dashboards. See ",(0,r.yg)("a",{parentName:"td",href:"#pages-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"pages")))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"pageinfo"},(0,r.yg)("inlineCode",{parentName:"h2"},"PageInfo")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your dashboard title, displayed in the header and browser tab")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"description"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Description of your dashboard, also displayed as a subtitle")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"navLinks"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional list of a maximum of 6 links, which will be displayed in the navigation bar. See ",(0,r.yg)("a",{parentName:"td",href:"#pageinfonavlinks-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"navLinks")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"footerText"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Text to display in the footer (note that this will override the default footer content). This can also include HTML and inline CSS")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"logo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The path to an image to display in the header (to the right of the title). This can be either local, where ",(0,r.yg)("inlineCode",{parentName:"td"},"/")," is the root of ",(0,r.yg)("inlineCode",{parentName:"td"},"./public"),", or any remote image, such as ",(0,r.yg)("inlineCode",{parentName:"td"},"https://i.ibb.co/yhbt6CY/dashy.png"),". It's recommended to scale your image down, so that it doesn't impact load times")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"pageinfonavlinks-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"pageInfo.navLinks")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The text to display on the link button")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"path"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to navigate to when clicked. Can be relative (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"/about"),") or absolute (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"https://example.com")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"http://192.168.1.1"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"target"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The opening method (external links only). Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"top")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"parent"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"pages-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"pages[]")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"name"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A unique name for that page")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"path"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The path (local or remote) to the config file to use.",(0,r.yg)("br",null),"For files located within ",(0,r.yg)("inlineCode",{parentName:"td"},"/public"),", you only need to specify filename, for externally hosted files you must include the full URL")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfig-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"language"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The 2 (or 4-digit) ",(0,r.yg)("a",{parentName:"td",href:"https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"},"ISO 639-1 code")," for your language, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"en")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"en-GB"),". This must be a language that the app has already been ",(0,r.yg)("a",{parentName:"td",href:"https://github.com/Lissy93/dashy/tree/master/src/assets/locales"},"translated")," into. If your language is unavailable, Dashy will fallback to English. By default Dashy will attempt to auto-detect your language, although this may not work on some privacy browsers.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"startingView"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Which page to load by default, and on the base page or domain root. You can still switch to different views from within the UI. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"default"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"minimal")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"default"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"defaultOpeningMethod"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The default opening method for items, if no ",(0,r.yg)("inlineCode",{parentName:"td"},"target")," is specified for a given item. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"modal"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"clipboard"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"top")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"parent"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheck"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"When set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", Dashy will ping each of your services and display their status as a dot next to each item. This can be overridden by setting ",(0,r.yg)("inlineCode",{parentName:"td"},"statusCheck")," under each item. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckInterval"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of seconds between checks. If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"0")," then service will only be checked on initial page load, which is usually the desired functionality. If value is less than ",(0,r.yg)("inlineCode",{parentName:"td"},"10")," you may experience a hit in performance. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"0"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"webSearch"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Configuration options for the web search feature, set your default search engine, opening method or disable web search. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfigwebsearch-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"webSearch")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"backgroundImg"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Path to an optional full-screen app background image. This can be either remote (http) or local (relative to /app/public/item-icons/ inside the container). Note that this will slow down initial load")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableFontAwesome"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," font-awesome will be loaded, if set to ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," they will not be. if left blank font-awesome will be enabled only if required by 1 or more icons")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableMaterialDesignIcons"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," mdi icons will be loaded, if set to ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," they will not be. Where ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," is enabled, if left blank material design icons will be enabled only if required by 1 or more icons")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"fontAwesomeKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"13014ae648"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"faviconApi"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only applicable if you are using favicons for item icons. Specifies which service to use to resolve favicons. Set to ",(0,r.yg)("inlineCode",{parentName:"td"},"local")," to do this locally, without using an API. Services running locally will use this option always. Available options are: ",(0,r.yg)("inlineCode",{parentName:"td"},"local"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"faviconkit"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"iconhorse"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"google"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"clearbit"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"webmasterapi")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"allesedv"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"faviconkit"),". See ",(0,r.yg)("a",{parentName:"td",href:"/docs/icons#favicons"},"Icons")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"auth"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"All settings relating to user authentication. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfigauth-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"auth")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"defaultIcon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An icon to be applied to any items, which don't already have an icon set. See ",(0,r.yg)("a",{parentName:"td",href:"/docs/icons#default-icon"},"Icon Docs")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"layout"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Layout for homepage, either ",(0,r.yg)("inlineCode",{parentName:"td"},"horizontal"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"vertical")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"),". This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified and overridden from the UI.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"iconSize"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The size of link items / icons. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"small"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"medium,")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"large"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"medium"),". This can also be set directly from the UI.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"colCount"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of columns of sections displayed on the homepage, using the default view. Should be in integer between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"8"),". Note that by default this is applied responsively, based on current screen size, and specifying a value here will override this behavior, which may not be desirable.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"theme"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The default theme for first load (you can change this later from the UI)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"cssThemes"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of custom theme names which can be used in the theme switcher dropdown")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customColors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Enables you to apply a custom color palette to any given theme. Use the theme name (lowercase) as the key, for an object including key-value-pairs, with the color variable name as keys, and 6-digit hex code as value. See ",(0,r.yg)("a",{parentName:"td",href:"/docs/theming#modifying-theme-colors"},"Theming")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"externalStyleSheet"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Either a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customCss"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Raw CSS that will be applied to the page. This can also be set from the UI. Please minify it first.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideComponents"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A list of key page components (header, footer, search, settings, etc) that are present by default, but can be removed using this option. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfighideComponents-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"appConfig.hideComponents")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"routingMode"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"hash")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"history"),". Determines the URL format for sub-pages, hash mode will look like ",(0,r.yg)("inlineCode",{parentName:"td"},"/#/home")," whereas with history mode available you have nice clean URLs, like ",(0,r.yg)("inlineCode",{parentName:"td"},"/home"),". For more info, see the ",(0,r.yg)("a",{parentName:"td",href:"https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations"},"Vue docs"),". If you're hosting Dashy with a custom BASE_URL, you will find that a bit of extra server config is necessary to get history mode working, so here you may want to instead use ",(0,r.yg)("inlineCode",{parentName:"td"},"hash")," mode.Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"history"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableMultiTasking"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, will keep apps open in the background when in the workspace view. Useful for quickly switching between multiple sites, and preserving their state, but comes at the cost of performance.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"workspaceLandingUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The URL or an app, service or website to launch when the workspace view is opened, before another service has been launched")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"preventWriteToDisk"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", users will be prevented from saving config changes to disk through the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"preventLocalSave"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", users will be prevented from applying config changes to local storage")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableConfiguration"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, no users will be able to view or edit the config through the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableConfigurationForNonAdmin"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, only admin users will be able to view or edit the config through the UI. disableConfiguration must not be set to true.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"widgetsAlwaysUseProxy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", requests made by widgets will always be proxied, same as setting ",(0,r.yg)("inlineCode",{parentName:"td"},"useProxy: true")," on each widget. Note that this may break some widgets.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showSplashScreen"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", a loading screen will be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableErrorReporting"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Enable reporting of unexpected errors and crashes. This is off by default, and ",(0,r.yg)("strong",{parentName:"td"},"no data will ever be captured unless you explicitly enable it"),". Turning on error reporting helps previously unknown bugs get discovered and fixed. Dashy uses ",(0,r.yg)("a",{parentName:"td",href:"https://github.com/getsentry/sentry"},"Sentry")," for error reporting. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sentryDsn"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you need to monitor errors in your instance, then you can use Sentry to collect and process bug reports. Sentry can be self-hosted, or used as SaaS, once your instance is setup, then all you need to do is pass in the DSN here, and enable error reporting. You can learn more on the ",(0,r.yg)("a",{parentName:"td",href:"https://docs.sentry.io/product/sentry-basics/dsn-explainer/"},"Sentry DSN Docs"),". Note that this will only ever be used if ",(0,r.yg)("inlineCode",{parentName:"td"},"enableErrorReporting")," is explicitly enabled.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableSmartSort"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"For the most-used and last-used app sort functions to work, a basic open-count is stored in local storage. If you do not want this to happen, then disable smart sort here, but you wil no longer be able to use these sort options. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableUpdateChecks"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, Dashy will not check for updates. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableServiceWorker"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Service workers cache web applications to improve load times and offer basic offline functionality, and are enabled by default in Dashy. The service worker can sometimes cause older content to be cached, requiring the app to be hard-refreshed. If you do not want SW functionality, or are having issues with caching, set this property to ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," to disable all service workers.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableContextMenu"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the custom right-click context menu will be disabled. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfigauth-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.auth")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"users"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of objects containing usernames and hashed passwords. If this is not provided, then authentication will be off by default, and you will not need any credentials to access the app. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfigauthusers-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"appConfig.auth.users")),". ",(0,r.yg)("br",null),(0,r.yg)("strong",{parentName:"td"},"Note")," this method of authentication is handled on the client side, so for security critical situations, it is recommended to use an ",(0,r.yg)("a",{parentName:"td",href:"/docs/authentication#alternative-authentication-methods"},"alternate authentication method"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableKeycloak"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", then authentication using Keycloak will be enabled. Note that you need to have an instance running, and have also configured ",(0,r.yg)("inlineCode",{parentName:"td"},"auth.keycloak"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"keycloak"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Config options to point Dashy to your Keycloak server. Requires ",(0,r.yg)("inlineCode",{parentName:"td"},"enableKeycloak: true"),". See ",(0,r.yg)("a",{parentName:"td",href:"#appconfigauthkeycloak-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"auth.keycloak"))," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableGuestAccess"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"When set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", an unauthenticated user will be able to access the dashboard, with read-only access, without having to login. Requires ",(0,r.yg)("inlineCode",{parentName:"td"},"auth.users")," to be configured. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")))),(0,r.yg)("p",null,"For more info, see the ",(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"/docs/authentication"},"Authentication Docs"))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfigauthusers-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.auth.users")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"user"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Username to log in with")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hash"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A SHA-256 hashed password")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"type"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The user type, either admin or normal")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfigauthkeycloak-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.auth.keycloak")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"serverUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL (or URL/ IP + Port) where your keycloak server is running")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"realm"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The name of the realm (must already be created) that you want to use")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"clientId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The Client ID of the client you created for use with Dashy")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"legacySupport"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If using Keycloak 17 or older, then set this to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfigwebsearch-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.webSearch")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableWebSearch"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Web search is enabled by default, but can be disabled by setting this property to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"searchEngine"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set the key name for your search engine. Can also use a custom engine by setting this property to ",(0,r.yg)("inlineCode",{parentName:"td"},"custom"),". Currently supported: ",(0,r.yg)("inlineCode",{parentName:"td"},"duckduckgo"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"google"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"whoogle"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"qwant"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"startpage"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"searx-bar")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"searx-info"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"duckduckgo"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customSearchEngine"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"You can also use a custom search engine, or your own self-hosted instance. This requires ",(0,r.yg)("inlineCode",{parentName:"td"},"searchEngine: custom")," to be set. Then add the URL of your service, with GET query string included here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"openingMethod"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set your preferred opening method for search results: ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"searchBangs"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A key-value-pair set of custom search ",(0,r.yg)("em",{parentName:"td"},"bangs")," for redirecting query to a specific app or search engine. The key of each should be the bang you will type (typically starting with ",(0,r.yg)("inlineCode",{parentName:"td"},"/"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"!")," or ",(0,r.yg)("inlineCode",{parentName:"td"},":"),"), and value is the destination, either as a search engine key (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"reddit"),") or a URL with search parameters (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"https://en.wikipedia.org/w/?search="),")")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfighidecomponents-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.hideComponents")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideHeading"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the page title & sub-title will not be visible. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideNav"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the navigation menu will not be visible. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideSearch"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the search bar will not be visible. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideSettings"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the settings menu will be initially collapsed. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideFooter"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the footer will not be visible. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"section"},(0,r.yg)("inlineCode",{parentName:"h2"},"section")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"name"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The title for the section")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"icon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An single icon to be displayed next to the title. See ",(0,r.yg)("a",{parentName:"td",href:"#sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"a"},"section.icon")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"items"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of items to be displayed within the section. See ",(0,r.yg)("a",{parentName:"td",href:"#sectionitem"},(0,r.yg)("inlineCode",{parentName:"a"},"item")),". Sections must include either 1 or more items, or 1 or more widgets.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"widgets"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of widgets to be displayed within the section. See ",(0,r.yg)("a",{parentName:"td",href:"#sectionwidget-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"widget")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"displayData"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Meta-data to optionally override display settings for a given section. See ",(0,r.yg)("a",{parentName:"td",href:"#sectiondisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"displayData")))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectionitem"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.item")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The text to display/ title of a given item. Max length ",(0,r.yg)("inlineCode",{parentName:"td"},"18"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"description"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Additional info about an item, which is shown in the tooltip on hover, or visible on large tiles")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"url"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL / location of web address for when the item is clicked")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"icon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The icon for a given item. Can be a font-awesome icon, favicon, remote URL or local URL. See ",(0,r.yg)("a",{parentName:"td",href:"#sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"a"},"item.icon")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"target"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The opening method for when the item is clicked, either ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"modal"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"clipboard"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"top")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"parent"),". Where ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab")," will open the link in a new tab, ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab")," will open it in the current tab, and ",(0,r.yg)("inlineCode",{parentName:"td"},"modal")," will open a pop-up modal, ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace")," will open in the Workspace view and ",(0,r.yg)("inlineCode",{parentName:"td"},"clipboard")," will copy the URL to system clipboard (but not launch app). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hotkey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Give frequently opened applications a numeric hotkey, between ",(0,r.yg)("inlineCode",{parentName:"td"},"0 - 9"),". You can then just press that key to launch that application.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"tags"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A list of tags, which can be used for improved search")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheck"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"When set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", Dashy will ping the URL associated with the current service, and display its status as a dot next to the item. The value here will override ",(0,r.yg)("inlineCode",{parentName:"td"},"appConfig.statusCheck")," so you can turn off or on checks for a given service. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"appConfig.statusCheck"),", falls back to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've enabled ",(0,r.yg)("inlineCode",{parentName:"td"},"statusCheck"),", and want to use a different URL to what is defined under the item, then specify it here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckHeaders"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you're endpoint requires any specific headers for the status checking, then define them here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckAllowInsecure"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default, any request to insecure content will be blocked. Setting this option to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," will disable the ",(0,r.yg)("inlineCode",{parentName:"td"},"rejectUnauthorized")," option, enabling you to ping non-HTTPS services for the current item. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckAcceptCodes"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If your service's response code is anything other than 2xx, then you can opt to specify an alternative success code. E.g. if you expect your server to return 403, but still want the status indicator to be green, set this value to ",(0,r.yg)("inlineCode",{parentName:"td"},"403"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckMaxRedirects"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If your service redirects to another page, and you would like status checks to follow redirects, then specify the maximum number of redirects here. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"0")," / will not follow redirects")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"color"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An optional color for the text and font-awesome icon to be displayed in. Note that this will override the current theme and so may not display well")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"rel"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The value of the ",(0,r.yg)("inlineCode",{parentName:"td"},"rel")," attribute for the link. Useful for specifying the relationship between the target link/document and Dashy. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"noopener noreferrer"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"backgroundColor"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An optional background fill color for the that given item. Again, this will override the current theme and so might not display well against the background")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"provider"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The name of the provider for a given service, useful for when including hosted apps. In some themes, this is visible under the item name")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"displayData"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Meta-data to optionally override display settings for a given item. See ",(0,r.yg)("a",{parentName:"td",href:"#itemdisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"displayData")))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"itemdisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"item.displayData")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be visible to all users, except for those specified in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showForUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be hidden from all users, except for those specified in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForGuests"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be visible for logged in users, but not for guests (see ",(0,r.yg)("inlineCode",{parentName:"td"},"appConfig.enableGuestAccess"),"). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForKeycloakUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be visible to all keycloak users, except for those configured via these groups and roles. See ",(0,r.yg)("inlineCode",{parentName:"td"},"hideForKeycloakUsers"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showForKeycloakUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be hidden from all keycloak users, except for those configured via these groups and roles. See ",(0,r.yg)("inlineCode",{parentName:"td"},"showForKeycloakUsers"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectionwidgets-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.widgets")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"type"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The widget type. See ",(0,r.yg)("a",{parentName:"td",href:"/docs/widgets"},"Widget Docs")," for full list of supported widgets")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"options"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Some widgets accept either optional or required additional options. Again, see the ",(0,r.yg)("a",{parentName:"td",href:"/docs/widgets"},"Widget Docs")," for full list of options")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"updateInterval"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"You can keep a widget constantly updated by specifying an update interval, in seconds. See ",(0,r.yg)("a",{parentName:"td",href:"/docs/widgets#continuous-updates"},"Continuous Updates Docs")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"useProxy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Some widgets make API requests to services that are not CORS-enabled. For these instances, you will need to route requests through a proxy, Dashy has a built in CORS-proxy, which you can use by setting this option to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),". See the ",(0,r.yg)("a",{parentName:"td",href:"/docs/widgets#proxying-requests"},"Proxying Requests Docs")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"timeout"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Request timeout in milliseconds, defaults to \xbd a second (",(0,r.yg)("inlineCode",{parentName:"td"},"500"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"ignoreErrors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Prevent an error message being displayed, if a network request or something else fails. Useful for false-positives")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"label"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Add custom label to a given widget. Useful for identification, if there are multiple of the same type of widget in a single section")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectiondisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.displayData")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The sort order for items within the current section. By default items are displayed in the order in which they are listed in within the config. The following sort options are supported: ",(0,r.yg)("inlineCode",{parentName:"td"},"most-used")," (most opened apps first), ",(0,r.yg)("inlineCode",{parentName:"td"},"last-used")," (the most recently used apps), ",(0,r.yg)("inlineCode",{parentName:"td"},"alphabetical"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"reverse-alphabetical"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"random")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"default"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"collapsed"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If true, the section will be collapsed initially, and will need to be clicked to open. Useful for less regularly used, or very long sections. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"cutToHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default, sections will fill available space. Set this option to true to match section height with content height")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"rows"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Height of the section, specified as the number of rows it should span vertically, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"2"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"1"),". Max is ",(0,r.yg)("inlineCode",{parentName:"td"},"5"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"cols"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Width of the section, specified as the number of columns the section should span horizontally, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"2"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"1"),". Max is ",(0,r.yg)("inlineCode",{parentName:"td"},"5"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"itemSize"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the size for items within this group, either ",(0,r.yg)("inlineCode",{parentName:"td"},"small"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"medium")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"large"),". Note that this will override any settings specified through the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"color"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A custom accent color for the section, as a hex code or HTML color (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"#fff"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customStyles"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Custom CSS properties that should be applied to that section, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"border: 2px dashed #ff0000;"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sectionLayout"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify which CSS layout will be used to responsively place items. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"auto")," (which uses flex layout), or ",(0,r.yg)("inlineCode",{parentName:"td"},"grid"),". If ",(0,r.yg)("inlineCode",{parentName:"td"},"grid")," is selected, then ",(0,r.yg)("inlineCode",{parentName:"td"},"itemCountX")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"itemCountY")," may also be set. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"itemCountX"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of items to display per row / horizontally. If not set, it will be calculated automatically based on available space. Can only be set if ",(0,r.yg)("inlineCode",{parentName:"td"},"sectionLayout")," is set to ",(0,r.yg)("inlineCode",{parentName:"td"},"grid"),". Must be a whole number between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"12"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"itemCountY"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of items to display per column / vertically. If not set, it will be calculated automatically based on available space. If ",(0,r.yg)("inlineCode",{parentName:"td"},"itemCountX")," is set, then ",(0,r.yg)("inlineCode",{parentName:"td"},"itemCountY")," can be calculated automatically. Can only be set if ",(0,r.yg)("inlineCode",{parentName:"td"},"sectionLayout")," is set to ",(0,r.yg)("inlineCode",{parentName:"td"},"grid"),". Must be a whole number between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"12"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be visible to all users, except for those specified in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showForUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be hidden from all users, except for those specified in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForGuests"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be visible for logged in users, but not for guests (see ",(0,r.yg)("inlineCode",{parentName:"td"},"appConfig.enableGuestAccess"),"). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForKeycloakUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be visible to all keycloak users, except for those configured via these groups and roles. See ",(0,r.yg)("inlineCode",{parentName:"td"},"hideForKeycloakUsers"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showForKeycloakUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be hidden from all keycloak users, except for those configured via these groups and roles. See ",(0,r.yg)("inlineCode",{parentName:"td"},"showForKeycloakUsers"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.icon")," and ",(0,r.yg)("inlineCode",{parentName:"h2"},"section.item.icon")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"icon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The icon for a given item or section. ",(0,r.yg)("br",null),"See ",(0,r.yg)("a",{parentName:"td",href:"/docs/icons"},"Icon Docs")," for all available supported icon types, including: auto-fetched favicons, generative icons, emoji icons, home-lab service logos, font-awesome, simple-icons, material icons, and icons specified by URL")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.displayData.hideForKeycloakUsers"),", ",(0,r.yg)("inlineCode",{parentName:"h2"},"section.displayData.showForKeycloakUsers"),", ",(0,r.yg)("inlineCode",{parentName:"h2"},"item.displayData.hideForKeycloakUsers")," and ",(0,r.yg)("inlineCode",{parentName:"h2"},"item.displayData.showForKeycloakUsers")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"groups"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current Section or Item will be hidden or shown based on the user having any of the groups in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"roles"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current Section or Item will be hidden or shown based on the user having any of the roles in this list")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"notes"},"Notes"),(0,r.yg)("h3",{id:"editing-config-through-the-ui"},"Editing Config through the UI"),(0,r.yg)("p",null,"Config can be modified directly through the UI, and then written to disk, or applied locally. This can be done wither with the raw config editor (introduced in V 0.6.5 / ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/pull/3"},"#3"),"), or the interactive editor (introduced in V 1.8.9 / ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/pull/298"},"#298"),")."),(0,r.yg)("p",{align:"center"},(0,r.yg)("a",{href:"https://ibb.co/CzkyMNb"},(0,r.yg)("b",null,"Interactive Editor"),(0,r.yg)("br",null),(0,r.yg)("img",{alt:"Interactive Editor demo",src:"https://user-images.githubusercontent.com/1862727/139543020-b0576d28-0830-476f-afc8-a815d4de6def.gif",width:"600"})),(0,r.yg)("br",null),(0,r.yg)("a",{href:"https://ibb.co/zRv542H"},(0,r.yg)("b",null,"JSON Editor"),(0,r.yg)("br",null),(0,r.yg)("img",{alt:"Config Editor demo",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/config-editor-demo.gif",width:"600"}))),(0,r.yg)("h3",{id:"about-yaml"},"About YAML"),(0,r.yg)("p",null,"If you're new to YAML, it's pretty straight-forward. The format is exactly the same as that of JSON, but instead of using curly braces, structure is denoted using whitespace. This ",(0,r.yg)("a",{parentName:"p",href:"https://linuxhandbook.com/yaml-basics/"},"quick guide")," should get you up to speed in a few minutes, for more advanced topics take a look at this ",(0,r.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/YAML"},"Wikipedia article"),"."),(0,r.yg)("h3",{id:"config-saving-methods"},"Config Saving Methods"),(0,r.yg)("p",null,"When updating the config through the JSON editor in the UI, you have two save options: ",(0,r.yg)("strong",{parentName:"p"},"Local")," or ",(0,r.yg)("strong",{parentName:"p"},"Write to Disk"),"."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Changes saved locally will only be applied to the current user through the browser, and will not apply to other instances - you either need to use the cloud sync feature, or manually update the conf.yml file."),(0,r.yg)("li",{parentName:"ul"},"On the other-hand, if you choose to write changes to disk, then your main ",(0,r.yg)("inlineCode",{parentName:"li"},"conf.yml")," file will be updated, and changes will be applied to all users, and visible across all devices. For this functionality to work, you must be running Dashy with using the Docker container, or the Node server. A backup of your current configuration will also be saved in the same directory.")),(0,r.yg)("h3",{id:"preventing-changes"},"Preventing Changes"),(0,r.yg)("p",null,"If you have authentication set up, then any user who is not an admin (with ",(0,r.yg)("inlineCode",{parentName:"p"},"type: admin"),") will not be able to write changes to disk."),(0,r.yg)("p",null,"You can also prevent changes from any user being written to disk, using ",(0,r.yg)("inlineCode",{parentName:"p"},"preventWriteToDisk"),". Or prevent any changes from being saved locally in browser storage, using ",(0,r.yg)("inlineCode",{parentName:"p"},"preventLocalSave"),"."),(0,r.yg)("p",null,"To disable all UI config features, set ",(0,r.yg)("inlineCode",{parentName:"p"},"disableConfiguration"),". Alternatively you can disable UI config features for all non Admin users by setting ",(0,r.yg)("inlineCode",{parentName:"p"},"disableConfigurationForNonAdmin")," to true."),(0,r.yg)("h3",{id:"example"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"---\npageInfo:\n title: Home Lab\nsections: # An array of sections\n- name: Section 1 - Getting Started\n items: # An array of items\n - title: GitHub\n description: Source code and documentation on GitHub\n icon: fab fa-github\n url: https://github.com/Lissy93/dashy\n - title: Issues\n description: View currently open issues, or raise a new one\n icon: fas fa-bug\n url: https://github.com/Lissy93/dashy/issues\n - title: Demo\n description: A live demo\n icon: far fa-rocket\n url: https://dashy-demo-1.netlify.app\n- name: Section 2 - Local Services\n items:\n - title: Firewall\n icon: favicon\n url: http://192.168.1.1/\n - title: Game Server\n icon: https://i.ibb.co/710B3Yc/space-invader-x256.png\n url: http://192.168.130.1/\n")),(0,r.yg)("p",null,"For more example config files, see: ",(0,r.yg)("a",{parentName:"p",href:"https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10"},"this gist")),(0,r.yg)("p",null,"If you need any help, feel free to ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/new?assignees=Lissy93&labels=%F0%9F%A4%B7%E2%80%8D%E2%99%82%EF%B8%8F+Question&template=question.md&title=%5BQUESTION%5D"},"Raise an Issue")," or ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions"},"Start a Discussion")),(0,r.yg)("p",null,"Happy Configuring \ud83e\udd13\ud83d\udd27"),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#configuring"},"\u2b06\ufe0f Back to Top"))))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4bdb0d83.5a2453b6.js b/assets/js/4bdb0d83.5a2453b6.js new file mode 100644 index 00000000..ffc1a097 --- /dev/null +++ b/assets/js/4bdb0d83.5a2453b6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[496],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>N});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var g=a.createContext({}),d=function(e){var t=a.useContext(g),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(g.Provider,{value:t},e.children)},y="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},s=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,g=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),y=d(n),s=r,N=y["".concat(g,".").concat(s)]||y[s]||m[s]||i;return n?a.createElement(N,l(l({ref:t},p),{},{components:n})):a.createElement(N,l({ref:t},p))}));function N(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=s;var o={};for(var g in t)hasOwnProperty.call(t,g)&&(o[g]=t[g]);o.originalType=e,o[y]="string"==typeof e?e:r,l[1]=o;for(var d=2;d{n.r(t),n.d(t,{contentTitle:()=>l,default:()=>y,frontMatter:()=>i,metadata:()=>o,toc:()=>g});var a=n(8168),r=(n(6540),n(5680));const i={},l="Configuring",o={unversionedId:"configuring",id:"configuring",isDocsHomePage:!1,title:"Configuring",description:"All app configuration is specified in /public/conf.yml which is in YAML Format format. If you're using Docker, this file can be passed in as a volume. Changes can either be made directly to this file, or done through the UI. From the UI you can also export, backup, reset, validate and download your configuration file.",source:"@site/docs/configuring.md",sourceDirName:".",slug:"/configuring",permalink:"/docs/configuring",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/configuring.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Deployment",permalink:"/docs/deployment"},next:{title:"App Management",permalink:"/docs/management"}},g=[{value:"There are three ways to edit the config",id:"there-are-three-ways-to-edit-the-config",children:[]},{value:"Tips",id:"tips",children:[]},{value:"Contents",id:"contents",children:[]},{value:"Top-Level Fields",id:"top-level-fields",children:[]},{value:"PageInfo",id:"pageinfo",children:[]},{value:"pageInfo.navLinks (optional)",id:"pageinfonavlinks-optional",children:[]},{value:"pages[] (optional)",id:"pages-optional",children:[]},{value:"appConfig (optional)",id:"appconfig-optional",children:[]},{value:"appConfig.auth (optional)",id:"appconfigauth-optional",children:[]},{value:"appConfig.auth.users (optional)",id:"appconfigauthusers-optional",children:[]},{value:"appConfig.auth.keycloak (optional)",id:"appconfigauthkeycloak-optional",children:[]},{value:"appConfig.webSearch (optional)",id:"appconfigwebsearch-optional",children:[]},{value:"appConfig.hideComponents (optional)",id:"appconfighidecomponents-optional",children:[]},{value:"section",id:"section",children:[]},{value:"section.item",id:"sectionitem",children:[]},{value:"item.displayData (optional)",id:"itemdisplaydata-optional",children:[]},{value:"section.widgets (optional)",id:"sectionwidgets-optional",children:[]},{value:"section.displayData (optional)",id:"sectiondisplaydata-optional",children:[]},{value:"section.icon and section.item.icon",id:"sectionicon-and-sectionitemicon",children:[]},{value:"section.displayData.hideForKeycloakUsers, section.displayData.showForKeycloakUsers, item.displayData.hideForKeycloakUsers and item.displayData.showForKeycloakUsers",id:"sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers",children:[]},{value:"Notes",id:"notes",children:[{value:"Editing Config through the UI",id:"editing-config-through-the-ui",children:[]},{value:"About YAML",id:"about-yaml",children:[]},{value:"Config Saving Methods",id:"config-saving-methods",children:[]},{value:"Preventing Changes",id:"preventing-changes",children:[]},{value:"Example",id:"example",children:[]}]}],d={toc:g},p="wrapper";function y(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,a.A)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"configuring"},"Configuring"),(0,r.yg)("p",null,"All app configuration is specified in ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/public/conf.yml"},(0,r.yg)("inlineCode",{parentName:"a"},"/public/conf.yml"))," which is in ",(0,r.yg)("a",{parentName:"p",href:"https://yaml.org/"},"YAML Format")," format. If you're using Docker, this file can be passed in as a volume. Changes can either be made directly to this file, or done ",(0,r.yg)("a",{parentName:"p",href:"#editing-config-through-the-ui"},"through the UI"),". From the UI you can also export, backup, reset, validate and download your configuration file."),(0,r.yg)("h2",{id:"there-are-three-ways-to-edit-the-config"},"There are three ways to edit the config"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Directly in the YAML file")," ",(0,r.yg)("em",{parentName:"li"},"(5/5 reliability, 3/5 usability)"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Write changes directly to the conf.yml file, optionally using one of the templates provided. This can be done in your favorite editor and uploading to your server, or directly editing the file via SSH, but the easiest method would be to use ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/coder/code-server"},"Code Server")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"UI JSON Editor")," ",(0,r.yg)("em",{parentName:"li"},"(4/5 reliability, 4/5 usability)"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"From the UI, under the config menu there is a JSON editor, with built-in validation, documentation and advanced options"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"UI Visual Editor")," ",(0,r.yg)("em",{parentName:"li"},"(3/5 reliability, 5/5 usability)"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"From the UI, enter the Interactive Edit Mode, then click any part of the page to edit. Changes are previewed live, and then saved to disk"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"REST API")," ",(0,r.yg)("em",{parentName:"li"},"(Coming soon)"),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Programmatically edit config either through the command line, using a script or a third-party application")))),(0,r.yg)("h2",{id:"tips"},"Tips"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"You may find it helpful to look at some sample config files to get you started, a collection of which can be found ",(0,r.yg)("a",{parentName:"li",href:"https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10"},"here")),(0,r.yg)("li",{parentName:"ul"},"You can check that your config file fits the schema, by running ",(0,r.yg)("inlineCode",{parentName:"li"},"yarn validate-config")),(0,r.yg)("li",{parentName:"ul"},"After modifying your config, the app needs to be recompiled, by running ",(0,r.yg)("inlineCode",{parentName:"li"},"yarn build")," - this happens automatically if you're using Docker"),(0,r.yg)("li",{parentName:"ul"},"It is recommended to keep a backup of your config file. You can download it under Config menu, or use the ",(0,r.yg)("a",{parentName:"li",href:"/docs/backup-restore"},"Cloud Backup")," feature."),(0,r.yg)("li",{parentName:"ul"},"You can make use of YAML features, like anchors, comments, multi-line strings, etc to reuse attributes and keep your config file readable"),(0,r.yg)("li",{parentName:"ul"},"Once you have finished configuring your dashboard, you can choose to ",(0,r.yg)("a",{parentName:"li",href:"#preventing-changes"},"disable UI config")," if you wish"),(0,r.yg)("li",{parentName:"ul"},"All fields are optional, unless otherwise stated.")),(0,r.yg)("p",null,"The following file provides a reference of all supported configuration options."),(0,r.yg)("h2",{id:"contents"},"Contents"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pageinfo"},(0,r.yg)("strong",{parentName:"a"},(0,r.yg)("inlineCode",{parentName:"strong"},"pageInfo")))," - Header text, footer, title, navigation, etc",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pageinfonavlinks-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"navLinks"))," - Links to display in the navigation bar"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pages-optional"},(0,r.yg)("strong",{parentName:"a"},(0,r.yg)("inlineCode",{parentName:"strong"},"pages")))," - List of additional config files, for multi-page dashboards"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfig-optional"},(0,r.yg)("strong",{parentName:"a"},(0,r.yg)("inlineCode",{parentName:"strong"},"appConfig")))," - Main application settings",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfigwebsearch-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"webSearch"))," - Configure web search engine options"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfighidecomponents-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"hideComponents"))," - Show/ hide page components"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfigauth-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"auth"))," - Built-in authentication setup",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfigauthusers-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"users"))," - List or users (for simple auth)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#appconfigauthkeycloak-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"keycloak"))," - Auth config for Keycloak"))))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#section"},(0,r.yg)("strong",{parentName:"a"},(0,r.yg)("inlineCode",{parentName:"strong"},"sections")))," - List of sections",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectiondisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"displayData"))," - Section display settings",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers"},(0,r.yg)("inlineCode",{parentName:"a"},"show/hideForKeycloakUsers"))," - Set user controls"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"a"},"icon"))," - Icon for a section"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectionitem"},(0,r.yg)("inlineCode",{parentName:"a"},"items"))," - List of items",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"a"},"icon"))," - Icon for an item"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#itemdisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"displayData"))," - Item display settings",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers"},(0,r.yg)("inlineCode",{parentName:"a"},"show/hideForKeycloakUsers"))," - Set user controls"))))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sectionwidget-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"widgets"))," - List of widgets"))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#notes"},(0,r.yg)("strong",{parentName:"a"},"Notes")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#editing-config-through-the-ui"},"Editing Config through the UI")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#about-yaml"},"About YAML")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#config-saving-methods"},"Config Saving Methods")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#preventing-changes"},"Preventing Changes")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#example"},"Example"))))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"top-level-fields"},"Top-Level Fields"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"pageInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Basic meta data like title, description, nav bar links, footer text. See ",(0,r.yg)("a",{parentName:"td",href:"#pageinfo"},(0,r.yg)("inlineCode",{parentName:"a"},"pageInfo")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"appConfig"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Settings related to how the app functions, including API keys and global styles. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfig-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"appConfig")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sections"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"An array of sections, each containing an array of items, which will be displayed as links. See ",(0,r.yg)("a",{parentName:"td",href:"#section"},(0,r.yg)("inlineCode",{parentName:"a"},"section")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"pages"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array additional config files, used for multi-page dashboards. See ",(0,r.yg)("a",{parentName:"td",href:"#pages-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"pages")))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"pageinfo"},(0,r.yg)("inlineCode",{parentName:"h2"},"PageInfo")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your dashboard title, displayed in the header and browser tab")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"description"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Description of your dashboard, also displayed as a subtitle")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"navLinks"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional list of a maximum of 6 links, which will be displayed in the navigation bar. See ",(0,r.yg)("a",{parentName:"td",href:"#pageinfonavlinks-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"navLinks")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"footerText"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Text to display in the footer (note that this will override the default footer content). This can also include HTML and inline CSS")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"logo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The path to an image to display in the header (to the right of the title). This can be either local, where ",(0,r.yg)("inlineCode",{parentName:"td"},"/")," is the root of ",(0,r.yg)("inlineCode",{parentName:"td"},"./public"),", or any remote image, such as ",(0,r.yg)("inlineCode",{parentName:"td"},"https://i.ibb.co/yhbt6CY/dashy.png"),". It's recommended to scale your image down, so that it doesn't impact load times")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"pageinfonavlinks-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"pageInfo.navLinks")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The text to display on the link button")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"path"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to navigate to when clicked. Can be relative (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"/about"),") or absolute (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"https://example.com")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"http://192.168.1.1"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"target"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The opening method (external links only). Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"top")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"parent"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"pages-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"pages[]")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"name"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A unique name for that page")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"path"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The path (local or remote) to the config file to use.",(0,r.yg)("br",null),"For files located within ",(0,r.yg)("inlineCode",{parentName:"td"},"/public"),", you only need to specify filename, for externally hosted files you must include the full URL")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfig-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"language"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The 2 (or 4-digit) ",(0,r.yg)("a",{parentName:"td",href:"https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"},"ISO 639-1 code")," for your language, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"en")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"en-GB"),". This must be a language that the app has already been ",(0,r.yg)("a",{parentName:"td",href:"https://github.com/Lissy93/dashy/tree/master/src/assets/locales"},"translated")," into. If your language is unavailable, Dashy will fallback to English. By default Dashy will attempt to auto-detect your language, although this may not work on some privacy browsers.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"startingView"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Which page to load by default, and on the base page or domain root. You can still switch to different views from within the UI. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"default"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"minimal")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"default"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"defaultOpeningMethod"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The default opening method for items, if no ",(0,r.yg)("inlineCode",{parentName:"td"},"target")," is specified for a given item. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"modal"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"clipboard"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"top")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"parent"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheck"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"When set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", Dashy will ping each of your services and display their status as a dot next to each item. This can be overridden by setting ",(0,r.yg)("inlineCode",{parentName:"td"},"statusCheck")," under each item. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckInterval"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of seconds between checks. If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"0")," then service will only be checked on initial page load, which is usually the desired functionality. If value is less than ",(0,r.yg)("inlineCode",{parentName:"td"},"10")," you may experience a hit in performance. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"0"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"webSearch"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Configuration options for the web search feature, set your default search engine, opening method or disable web search. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfigwebsearch-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"webSearch")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"backgroundImg"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Path to an optional full-screen app background image. This can be either remote (http) or local (relative to /app/public/item-icons/ inside the container). Note that this will slow down initial load")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableFontAwesome"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," font-awesome will be loaded, if set to ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," they will not be. if left blank font-awesome will be enabled only if required by 1 or more icons")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableMaterialDesignIcons"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," mdi icons will be loaded, if set to ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," they will not be. Where ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," is enabled, if left blank material design icons will be enabled only if required by 1 or more icons")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"fontAwesomeKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"13014ae648"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"faviconApi"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only applicable if you are using favicons for item icons. Specifies which service to use to resolve favicons. Set to ",(0,r.yg)("inlineCode",{parentName:"td"},"local")," to do this locally, without using an API. Services running locally will use this option always. Available options are: ",(0,r.yg)("inlineCode",{parentName:"td"},"local"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"faviconkit"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"iconhorse"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"google"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"clearbit"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"webmasterapi")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"allesedv"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"faviconkit"),". See ",(0,r.yg)("a",{parentName:"td",href:"/docs/icons#favicons"},"Icons")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"auth"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"All settings relating to user authentication. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfigauth-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"auth")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"defaultIcon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An icon to be applied to any items, which don't already have an icon set. See ",(0,r.yg)("a",{parentName:"td",href:"/docs/icons#default-icon"},"Icon Docs")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"layout"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Layout for homepage, either ",(0,r.yg)("inlineCode",{parentName:"td"},"horizontal"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"vertical")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"),". This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified and overridden from the UI.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"iconSize"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"enum")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The size of link items / icons. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"small"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"medium,")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"large"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"medium"),". This can also be set directly from the UI.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"colCount"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of columns of sections displayed on the homepage, using the default view. Should be in integer between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"8"),". Note that by default this is applied responsively, based on current screen size, and specifying a value here will override this behavior, which may not be desirable.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"theme"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The default theme for first load (you can change this later from the UI)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"cssThemes"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of custom theme names which can be used in the theme switcher dropdown")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customColors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Enables you to apply a custom color palette to any given theme. Use the theme name (lowercase) as the key, for an object including key-value-pairs, with the color variable name as keys, and 6-digit hex code as value. See ",(0,r.yg)("a",{parentName:"td",href:"/docs/theming#modifying-theme-colors"},"Theming")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"externalStyleSheet"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Either a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customCss"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Raw CSS that will be applied to the page. This can also be set from the UI. Please minify it first.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideComponents"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A list of key page components (header, footer, search, settings, etc) that are present by default, but can be removed using this option. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfighideComponents-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"appConfig.hideComponents")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"routingMode"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"hash")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"history"),". Determines the URL format for sub-pages, hash mode will look like ",(0,r.yg)("inlineCode",{parentName:"td"},"/#/home")," whereas with history mode available you have nice clean URLs, like ",(0,r.yg)("inlineCode",{parentName:"td"},"/home"),". For more info, see the ",(0,r.yg)("a",{parentName:"td",href:"https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations"},"Vue docs"),". If you're hosting Dashy with a custom BASE_URL, you will find that a bit of extra server config is necessary to get history mode working, so here you may want to instead use ",(0,r.yg)("inlineCode",{parentName:"td"},"hash")," mode.Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"history"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableMultiTasking"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, will keep apps open in the background when in the workspace view. Useful for quickly switching between multiple sites, and preserving their state, but comes at the cost of performance.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"workspaceLandingUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The URL or an app, service or website to launch when the workspace view is opened, before another service has been launched")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"preventWriteToDisk"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", users will be prevented from saving config changes to disk through the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"preventLocalSave"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", users will be prevented from applying config changes to local storage")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableConfiguration"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, no users will be able to view or edit the config through the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableConfigurationForNonAdmin"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, only admin users will be able to view or edit the config through the UI. disableConfiguration must not be set to true.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"widgetsAlwaysUseProxy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", requests made by widgets will always be proxied, same as setting ",(0,r.yg)("inlineCode",{parentName:"td"},"useProxy: true")," on each widget. Note that this may break some widgets.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showSplashScreen"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", a loading screen will be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableErrorReporting"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Enable reporting of unexpected errors and crashes. This is off by default, and ",(0,r.yg)("strong",{parentName:"td"},"no data will ever be captured unless you explicitly enable it"),". Turning on error reporting helps previously unknown bugs get discovered and fixed. Dashy uses ",(0,r.yg)("a",{parentName:"td",href:"https://github.com/getsentry/sentry"},"Sentry")," for error reporting. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sentryDsn"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you need to monitor errors in your instance, then you can use Sentry to collect and process bug reports. Sentry can be self-hosted, or used as SaaS, once your instance is setup, then all you need to do is pass in the DSN here, and enable error reporting. You can learn more on the ",(0,r.yg)("a",{parentName:"td",href:"https://docs.sentry.io/product/sentry-basics/dsn-explainer/"},"Sentry DSN Docs"),". Note that this will only ever be used if ",(0,r.yg)("inlineCode",{parentName:"td"},"enableErrorReporting")," is explicitly enabled.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableSmartSort"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"For the most-used and last-used app sort functions to work, a basic open-count is stored in local storage. If you do not want this to happen, then disable smart sort here, but you wil no longer be able to use these sort options. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableUpdateChecks"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, Dashy will not check for updates. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableServiceWorker"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Service workers cache web applications to improve load times and offer basic offline functionality, and are enabled by default in Dashy. The service worker can sometimes cause older content to be cached, requiring the app to be hard-refreshed. If you do not want SW functionality, or are having issues with caching, set this property to ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," to disable all service workers.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableContextMenu"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the custom right-click context menu will be disabled. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfigauth-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.auth")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"users"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of objects containing usernames and hashed passwords. If this is not provided, then authentication will be off by default, and you will not need any credentials to access the app. See ",(0,r.yg)("a",{parentName:"td",href:"#appconfigauthusers-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"appConfig.auth.users")),". ",(0,r.yg)("br",null),(0,r.yg)("strong",{parentName:"td"},"Note")," this method of authentication is handled on the client side, so for security critical situations, it is recommended to use an ",(0,r.yg)("a",{parentName:"td",href:"/docs/authentication#alternative-authentication-methods"},"alternate authentication method"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableKeycloak"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", then authentication using Keycloak will be enabled. Note that you need to have an instance running, and have also configured ",(0,r.yg)("inlineCode",{parentName:"td"},"auth.keycloak"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"keycloak"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Config options to point Dashy to your Keycloak server. Requires ",(0,r.yg)("inlineCode",{parentName:"td"},"enableKeycloak: true"),". See ",(0,r.yg)("a",{parentName:"td",href:"#appconfigauthkeycloak-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"auth.keycloak"))," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"enableGuestAccess"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"When set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", an unauthenticated user will be able to access the dashboard, with read-only access, without having to login. Requires ",(0,r.yg)("inlineCode",{parentName:"td"},"auth.users")," to be configured. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),".")))),(0,r.yg)("p",null,"For more info, see the ",(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"/docs/authentication"},"Authentication Docs"))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfigauthusers-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.auth.users")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"user"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Username to log in with")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hash"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A SHA-256 hashed password")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"type"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The user type, either admin or normal")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfigauthkeycloak-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.auth.keycloak")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"serverUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL (or URL/ IP + Port) where your keycloak server is running")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"realm"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The name of the realm (must already be created) that you want to use")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"clientId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The Client ID of the client you created for use with Dashy")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"legacySupport"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If using Keycloak 17 or older, then set this to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfigwebsearch-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.webSearch")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableWebSearch"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Web search is enabled by default, but can be disabled by setting this property to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"searchEngine"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set the key name for your search engine. Can also use a custom engine by setting this property to ",(0,r.yg)("inlineCode",{parentName:"td"},"custom"),". Currently supported: ",(0,r.yg)("inlineCode",{parentName:"td"},"duckduckgo"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"google"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"whoogle"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"qwant"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"startpage"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"searx-bar")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"searx-info"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"duckduckgo"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customSearchEngine"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"You can also use a custom search engine, or your own self-hosted instance. This requires ",(0,r.yg)("inlineCode",{parentName:"td"},"searchEngine: custom")," to be set. Then add the URL of your service, with GET query string included here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"openingMethod"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set your preferred opening method for search results: ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"searchBangs"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A key-value-pair set of custom search ",(0,r.yg)("em",{parentName:"td"},"bangs")," for redirecting query to a specific app or search engine. The key of each should be the bang you will type (typically starting with ",(0,r.yg)("inlineCode",{parentName:"td"},"/"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"!")," or ",(0,r.yg)("inlineCode",{parentName:"td"},":"),"), and value is the destination, either as a search engine key (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"reddit"),") or a URL with search parameters (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"https://en.wikipedia.org/w/?search="),")")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"appconfighidecomponents-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"appConfig.hideComponents")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideHeading"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the page title & sub-title will not be visible. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideNav"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the navigation menu will not be visible. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideSearch"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the search bar will not be visible. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideSettings"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the settings menu will be initially collapsed. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideFooter"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the footer will not be visible. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"section"},(0,r.yg)("inlineCode",{parentName:"h2"},"section")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"name"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The title for the section")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"icon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An single icon to be displayed next to the title. See ",(0,r.yg)("a",{parentName:"td",href:"#sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"a"},"section.icon")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"items"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of items to be displayed within the section. See ",(0,r.yg)("a",{parentName:"td",href:"#sectionitem"},(0,r.yg)("inlineCode",{parentName:"a"},"item")),". Sections must include either 1 or more items, or 1 or more widgets.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"widgets"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of widgets to be displayed within the section. See ",(0,r.yg)("a",{parentName:"td",href:"#sectionwidget-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"widget")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"displayData"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Meta-data to optionally override display settings for a given section. See ",(0,r.yg)("a",{parentName:"td",href:"#sectiondisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"displayData")))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectionitem"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.item")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The text to display/ title of a given item. Max length ",(0,r.yg)("inlineCode",{parentName:"td"},"18"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"description"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Additional info about an item, which is shown in the tooltip on hover, or visible on large tiles")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"url"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL / location of web address for when the item is clicked")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"icon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The icon for a given item. Can be a font-awesome icon, favicon, remote URL or local URL. See ",(0,r.yg)("a",{parentName:"td",href:"#sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"a"},"item.icon")))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"target"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The opening method for when the item is clicked, either ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"modal"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"clipboard"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"top")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"parent"),". Where ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab")," will open the link in a new tab, ",(0,r.yg)("inlineCode",{parentName:"td"},"sametab")," will open it in the current tab, and ",(0,r.yg)("inlineCode",{parentName:"td"},"modal")," will open a pop-up modal, ",(0,r.yg)("inlineCode",{parentName:"td"},"workspace")," will open in the Workspace view and ",(0,r.yg)("inlineCode",{parentName:"td"},"clipboard")," will copy the URL to system clipboard (but not launch app). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"newtab"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hotkey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Give frequently opened applications a numeric hotkey, between ",(0,r.yg)("inlineCode",{parentName:"td"},"0 - 9"),". You can then just press that key to launch that application.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"tags"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A list of tags, which can be used for improved search")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheck"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"When set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", Dashy will ping the URL associated with the current service, and display its status as a dot next to the item. The value here will override ",(0,r.yg)("inlineCode",{parentName:"td"},"appConfig.statusCheck")," so you can turn off or on checks for a given service. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"appConfig.statusCheck"),", falls back to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've enabled ",(0,r.yg)("inlineCode",{parentName:"td"},"statusCheck"),", and want to use a different URL to what is defined under the item, then specify it here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckHeaders"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you're endpoint requires any specific headers for the status checking, then define them here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckAllowInsecure"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default, any request to insecure content will be blocked. Setting this option to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," will disable the ",(0,r.yg)("inlineCode",{parentName:"td"},"rejectUnauthorized")," option, enabling you to ping non-HTTPS services for the current item. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckAcceptCodes"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If your service's response code is anything other than 2xx, then you can opt to specify an alternative success code. E.g. if you expect your server to return 403, but still want the status indicator to be green, set this value to ",(0,r.yg)("inlineCode",{parentName:"td"},"403"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"statusCheckMaxRedirects"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If your service redirects to another page, and you would like status checks to follow redirects, then specify the maximum number of redirects here. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"0")," / will not follow redirects")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"color"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An optional color for the text and font-awesome icon to be displayed in. Note that this will override the current theme and so may not display well")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"rel"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The value of the ",(0,r.yg)("inlineCode",{parentName:"td"},"rel")," attribute for the link. Useful for specifying the relationship between the target link/document and Dashy. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"noopener noreferrer"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"backgroundColor"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An optional background fill color for the that given item. Again, this will override the current theme and so might not display well against the background")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"provider"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The name of the provider for a given service, useful for when including hosted apps. In some themes, this is visible under the item name")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"displayData"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Meta-data to optionally override display settings for a given item. See ",(0,r.yg)("a",{parentName:"td",href:"#itemdisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"a"},"displayData")))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"itemdisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"item.displayData")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be visible to all users, except for those specified in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showForUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be hidden from all users, except for those specified in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForGuests"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be visible for logged in users, but not for guests (see ",(0,r.yg)("inlineCode",{parentName:"td"},"appConfig.enableGuestAccess"),"). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForKeycloakUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be visible to all keycloak users, except for those configured via these groups and roles. See ",(0,r.yg)("inlineCode",{parentName:"td"},"hideForKeycloakUsers"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showForKeycloakUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current item will be hidden from all keycloak users, except for those configured via these groups and roles. See ",(0,r.yg)("inlineCode",{parentName:"td"},"showForKeycloakUsers"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectionwidgets-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.widgets")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"type"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The widget type. See ",(0,r.yg)("a",{parentName:"td",href:"/docs/widgets"},"Widget Docs")," for full list of supported widgets")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"options"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Some widgets accept either optional or required additional options. Again, see the ",(0,r.yg)("a",{parentName:"td",href:"/docs/widgets"},"Widget Docs")," for full list of options")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"updateInterval"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"You can keep a widget constantly updated by specifying an update interval, in seconds. See ",(0,r.yg)("a",{parentName:"td",href:"/docs/widgets#continuous-updates"},"Continuous Updates Docs")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"useProxy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Some widgets make API requests to services that are not CORS-enabled. For these instances, you will need to route requests through a proxy, Dashy has a built in CORS-proxy, which you can use by setting this option to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"),". See the ",(0,r.yg)("a",{parentName:"td",href:"/docs/widgets#proxying-requests"},"Proxying Requests Docs")," for more info")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"timeout"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Request timeout in milliseconds, defaults to \xbd a second (",(0,r.yg)("inlineCode",{parentName:"td"},"500"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"ignoreErrors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Prevent an error message being displayed, if a network request or something else fails. Useful for false-positives")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"label"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Add custom label to a given widget. Useful for identification, if there are multiple of the same type of widget in a single section")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectiondisplaydata-optional"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.displayData")," ",(0,r.yg)("em",{parentName:"h2"},"(optional)")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The sort order for items within the current section. By default items are displayed in the order in which they are listed in within the config. The following sort options are supported: ",(0,r.yg)("inlineCode",{parentName:"td"},"most-used")," (most opened apps first), ",(0,r.yg)("inlineCode",{parentName:"td"},"last-used")," (the most recently used apps), ",(0,r.yg)("inlineCode",{parentName:"td"},"alphabetical"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"reverse-alphabetical"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"random")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"default"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"collapsed"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If true, the section will be collapsed initially, and will need to be clicked to open. Useful for less regularly used, or very long sections. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"cutToHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default, sections will fill available space. Set this option to true to match section height with content height")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"rows"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Height of the section, specified as the number of rows it should span vertically, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"2"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"1"),". Max is ",(0,r.yg)("inlineCode",{parentName:"td"},"5"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"cols"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Width of the section, specified as the number of columns the section should span horizontally, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"2"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"1"),". Max is ",(0,r.yg)("inlineCode",{parentName:"td"},"5"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"itemSize"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the size for items within this group, either ",(0,r.yg)("inlineCode",{parentName:"td"},"small"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"medium")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"large"),". Note that this will override any settings specified through the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"color"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A custom accent color for the section, as a hex code or HTML color (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"#fff"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customStyles"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Custom CSS properties that should be applied to that section, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"border: 2px dashed #ff0000;"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sectionLayout"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify which CSS layout will be used to responsively place items. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"auto")," (which uses flex layout), or ",(0,r.yg)("inlineCode",{parentName:"td"},"grid"),". If ",(0,r.yg)("inlineCode",{parentName:"td"},"grid")," is selected, then ",(0,r.yg)("inlineCode",{parentName:"td"},"itemCountX")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"itemCountY")," may also be set. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"itemCountX"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of items to display per row / horizontally. If not set, it will be calculated automatically based on available space. Can only be set if ",(0,r.yg)("inlineCode",{parentName:"td"},"sectionLayout")," is set to ",(0,r.yg)("inlineCode",{parentName:"td"},"grid"),". Must be a whole number between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"12"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"itemCountY"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of items to display per column / vertically. If not set, it will be calculated automatically based on available space. If ",(0,r.yg)("inlineCode",{parentName:"td"},"itemCountX")," is set, then ",(0,r.yg)("inlineCode",{parentName:"td"},"itemCountY")," can be calculated automatically. Can only be set if ",(0,r.yg)("inlineCode",{parentName:"td"},"sectionLayout")," is set to ",(0,r.yg)("inlineCode",{parentName:"td"},"grid"),". Must be a whole number between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"12"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be visible to all users, except for those specified in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showForUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be hidden from all users, except for those specified in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForGuests"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be visible for logged in users, but not for guests (see ",(0,r.yg)("inlineCode",{parentName:"td"},"appConfig.enableGuestAccess"),"). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideForKeycloakUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be visible to all keycloak users, except for those configured via these groups and roles. See ",(0,r.yg)("inlineCode",{parentName:"td"},"hideForKeycloakUsers"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showForKeycloakUsers"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current section will be hidden from all keycloak users, except for those configured via these groups and roles. See ",(0,r.yg)("inlineCode",{parentName:"td"},"showForKeycloakUsers"))))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectionicon-and-sectionitemicon"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.icon")," and ",(0,r.yg)("inlineCode",{parentName:"h2"},"section.item.icon")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"icon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The icon for a given item or section. ",(0,r.yg)("br",null),"See ",(0,r.yg)("a",{parentName:"td",href:"/docs/icons"},"Icon Docs")," for all available supported icon types, including: auto-fetched favicons, generative icons, emoji icons, home-lab service logos, font-awesome, simple-icons, material icons, and icons specified by URL")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("h2",{id:"sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers"},(0,r.yg)("inlineCode",{parentName:"h2"},"section.displayData.hideForKeycloakUsers"),", ",(0,r.yg)("inlineCode",{parentName:"h2"},"section.displayData.showForKeycloakUsers"),", ",(0,r.yg)("inlineCode",{parentName:"h2"},"item.displayData.hideForKeycloakUsers")," and ",(0,r.yg)("inlineCode",{parentName:"h2"},"item.displayData.showForKeycloakUsers")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"groups"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current Section or Item will be hidden or shown based on the user having any of the groups in this list")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"roles"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Current Section or Item will be hidden or shown based on the user having any of the roles in this list")))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"notes"},"Notes"),(0,r.yg)("h3",{id:"editing-config-through-the-ui"},"Editing Config through the UI"),(0,r.yg)("p",null,"Config can be modified directly through the UI, and then written to disk, or applied locally. This can be done wither with the raw config editor (introduced in V 0.6.5 / ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/pull/3"},"#3"),"), or the interactive editor (introduced in V 1.8.9 / ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/pull/298"},"#298"),")."),(0,r.yg)("p",{align:"center"},(0,r.yg)("a",{href:"https://ibb.co/CzkyMNb"},(0,r.yg)("b",null,"Interactive Editor"),(0,r.yg)("br",null),(0,r.yg)("img",{alt:"Interactive Editor demo",src:"https://user-images.githubusercontent.com/1862727/139543020-b0576d28-0830-476f-afc8-a815d4de6def.gif",width:"600"})),(0,r.yg)("br",null),(0,r.yg)("a",{href:"https://ibb.co/zRv542H"},(0,r.yg)("b",null,"JSON Editor"),(0,r.yg)("br",null),(0,r.yg)("img",{alt:"Config Editor demo",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/config-editor-demo.gif",width:"600"}))),(0,r.yg)("h3",{id:"about-yaml"},"About YAML"),(0,r.yg)("p",null,"If you're new to YAML, it's pretty straight-forward. The format is exactly the same as that of JSON, but instead of using curly braces, structure is denoted using whitespace. This ",(0,r.yg)("a",{parentName:"p",href:"https://linuxhandbook.com/yaml-basics/"},"quick guide")," should get you up to speed in a few minutes, for more advanced topics take a look at this ",(0,r.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/YAML"},"Wikipedia article"),"."),(0,r.yg)("h3",{id:"config-saving-methods"},"Config Saving Methods"),(0,r.yg)("p",null,"When updating the config through the JSON editor in the UI, you have two save options: ",(0,r.yg)("strong",{parentName:"p"},"Local")," or ",(0,r.yg)("strong",{parentName:"p"},"Write to Disk"),"."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Changes saved locally will only be applied to the current user through the browser, and will not apply to other instances - you either need to use the cloud sync feature, or manually update the conf.yml file."),(0,r.yg)("li",{parentName:"ul"},"On the other-hand, if you choose to write changes to disk, then your main ",(0,r.yg)("inlineCode",{parentName:"li"},"conf.yml")," file will be updated, and changes will be applied to all users, and visible across all devices. For this functionality to work, you must be running Dashy with using the Docker container, or the Node server. A backup of your current configuration will also be saved in the same directory.")),(0,r.yg)("h3",{id:"preventing-changes"},"Preventing Changes"),(0,r.yg)("p",null,"If you have authentication set up, then any user who is not an admin (with ",(0,r.yg)("inlineCode",{parentName:"p"},"type: admin"),") will not be able to write changes to disk."),(0,r.yg)("p",null,"You can also prevent changes from any user being written to disk, using ",(0,r.yg)("inlineCode",{parentName:"p"},"preventWriteToDisk"),". Or prevent any changes from being saved locally in browser storage, using ",(0,r.yg)("inlineCode",{parentName:"p"},"preventLocalSave"),"."),(0,r.yg)("p",null,"To disable all UI config features, set ",(0,r.yg)("inlineCode",{parentName:"p"},"disableConfiguration"),". Alternatively you can disable UI config features for all non Admin users by setting ",(0,r.yg)("inlineCode",{parentName:"p"},"disableConfigurationForNonAdmin")," to true."),(0,r.yg)("h3",{id:"example"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"---\npageInfo:\n title: Home Lab\nsections: # An array of sections\n- name: Section 1 - Getting Started\n items: # An array of items\n - title: GitHub\n description: Source code and documentation on GitHub\n icon: fab fa-github\n url: https://github.com/Lissy93/dashy\n - title: Issues\n description: View currently open issues, or raise a new one\n icon: fas fa-bug\n url: https://github.com/Lissy93/dashy/issues\n - title: Demo\n description: A live demo\n icon: far fa-rocket\n url: https://dashy-demo-1.netlify.app\n- name: Section 2 - Local Services\n items:\n - title: Firewall\n icon: favicon\n url: http://192.168.1.1/\n - title: Game Server\n icon: https://i.ibb.co/710B3Yc/space-invader-x256.png\n url: http://192.168.130.1/\n")),(0,r.yg)("p",null,"For more example config files, see: ",(0,r.yg)("a",{parentName:"p",href:"https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10"},"this gist")),(0,r.yg)("p",null,"If you need any help, feel free to ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/new?assignees=Lissy93&labels=%F0%9F%A4%B7%E2%80%8D%E2%99%82%EF%B8%8F+Question&template=question.md&title=%5BQUESTION%5D"},"Raise an Issue")," or ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions"},"Start a Discussion")),(0,r.yg)("p",null,"Happy Configuring \ud83e\udd13\ud83d\udd27"),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4d54d076.232023dd.js b/assets/js/4d54d076.be1fdcfc.js similarity index 97% rename from assets/js/4d54d076.232023dd.js rename to assets/js/4d54d076.be1fdcfc.js index 17cfcf9d..8f5cf711 100644 --- a/assets/js/4d54d076.232023dd.js +++ b/assets/js/4d54d076.be1fdcfc.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[459],{5680:(e,t,a)=>{a.d(t,{xA:()=>y,yg:()=>g});var s=a(6540);function o(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,s)}return a}function i(e){for(var t=1;t=0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(s=0;s=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(o[a]=e[a])}return o}var l=s.createContext({}),h=function(e){var t=s.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},y=function(e){var t=h(e.components);return s.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return s.createElement(s.Fragment,{},t)}},d=s.forwardRef((function(e,t){var a=e.components,o=e.mdxType,r=e.originalType,l=e.parentName,y=n(e,["components","mdxType","originalType","parentName"]),p=h(a),d=o,g=p["".concat(l,".").concat(d)]||p[d]||u[d]||r;return a?s.createElement(g,i(i({ref:t},y),{},{components:a})):s.createElement(g,i({ref:t},y))}));function g(e,t){var a=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=a.length,i=new Array(r);i[0]=d;var n={};for(var l in t)hasOwnProperty.call(t,l)&&(n[l]=t[l]);n.originalType=e,n[p]="string"==typeof e?e:o,i[1]=n;for(var h=2;h{a.r(t),a.d(t,{contentTitle:()=>i,default:()=>p,frontMatter:()=>r,metadata:()=>n,toc:()=>l});var s=a(8168),o=(a(6540),a(5680));const r={},i="Contributing",n={unversionedId:"contributing",id:"contributing",isDocsHomePage:!1,title:"Contributing",description:"First off, thank you for considering contributing towards Dashy! \ud83d\ude4c",source:"@site/docs/contributing.md",sourceDirName:".",slug:"/contributing",permalink:"/docs/contributing",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/contributing.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"*Dashy Showcase* \ud83c\udf1f",permalink:"/docs/showcase"},next:{title:"Developing",permalink:"/docs/developing"}},l=[{value:"Take a 2-minute survey",id:"take-a-2-minute-survey",children:[]},{value:"Share your dashboard",id:"share-your-dashboard",children:[]},{value:"Make a small donation",id:"make-a-small-donation",children:[]},{value:"Enable Anonymous Bug Reports",id:"enable-anonymous-bug-reports",children:[]},{value:"Add Translations",id:"add-translations",children:[]},{value:"Submit a PR",id:"submit-a-pr",children:[]},{value:"Improve the Docs",id:"improve-the-docs",children:[]},{value:"Raise a bug",id:"raise-a-bug",children:[]},{value:"Join the discussion",id:"join-the-discussion",children:[]},{value:"Request a feature via BountySource",id:"request-a-feature-via-bountysource",children:[]},{value:"Spread the word",id:"spread-the-word",children:[]},{value:"Star, Upvote or Leave a Review",id:"star-upvote-or-leave-a-review",children:[]},{value:"Follow for More",id:"follow-for-more",children:[{value:"Contributors",id:"contributors",children:[]},{value:"Star-Gazers Over Time",id:"star-gazers-over-time",children:[]}]}],h={toc:l},y="wrapper";function p(e){let{components:t,...a}=e;return(0,o.yg)(y,(0,s.A)({},h,a,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"contributing"},"Contributing"),(0,o.yg)("p",null,"First off, thank you for considering contributing towards Dashy! \ud83d\ude4c\nThere are several ways that you can help out, and any contributions, however small will always be very much appreciated.\nYou will be appropriately credited in the readme - huge thank you to ",(0,o.yg)("a",{parentName:"p",href:"/docs/credits"},"everyone who has helped")," so far \ud83d\udc9e"),(0,o.yg)("h2",{id:"take-a-2-minute-survey"},"Take a 2-minute survey"),(0,o.yg)("p",null,"Help improve Dashy by taking a very short, 6-question survey. This will give me a better understanding of what is important to you, so that I can make Dashy better in the future :)"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://survey.typeform.com/to/gl0L68ou"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Take_the-Survey-%231a86fd?style=for-the-badge&logo=buddy",alt:"Take the Survey"}))),(0,o.yg)("h2",{id:"share-your-dashboard"},"Share your dashboard"),(0,o.yg)("p",null,"Dashy now has a ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/showcase.md#dashy-showcase-"},"Showcase")," where you can show off a screenshot of your dashboard, and get inspiration from other users (and I really love seeing how people are using Dashy). To ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/showcase.md#submitting-your-dashboard"},"submit your dashboard"),", either open a PR or raise an issue."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/new?assignees=&labels=%F0%9F%92%AF+Showcase&template=showcase-addition.yml&title=%5BSHOWCASE%5D+%3Ctitle%3E"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Add_your_Dashboard-Showcase-%238616ee?style=for-the-badge&logo=feathub&logoColor=8616ee",alt:"Add your Dashboard to the Showcase"}))),(0,o.yg)("h2",{id:"make-a-small-donation"},"Make a small donation"),(0,o.yg)("p",null,"Donations help to cover server costs, development time and caffeine ;)\nDon't feel any pressure to donate anything, as Dashy and my other projects will always be 100% free, for everyone, for ever."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/sponsors/Lissy93"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Sponsor_on_GitHub-Lissy93-%23ff4dda?style=for-the-badge&logo=githubsponsors&logoColor=ff4dda",alt:"Sponsor Lissy93 on GitHub"}))),(0,o.yg)("p",null,"Sponsoring will give you several perks - for $1 / \xa30.75 per month, you'll get a sponsor badge on your profile, be credited on the Dashy's readme, with a link to your website/ profile/ socials, get priority support, have your feature ideas implemented, plus lots more. For more info, see ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/sponsors/Lissy93"},"@Lissy93's Sponsor Page"),"."),(0,o.yg)("h2",{id:"enable-anonymous-bug-reports"},"Enable Anonymous Bug Reports"),(0,o.yg)("p",null,"Bug reports helps me to discover bugs I was unaware of, and then fix them, in order to make Dashy more reliable long term. This is a simple, yet really helpful step you can take to help improve Dashy. ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/getsentry/sentry"},"Sentry")," is an open source error tracking and performance monitoring tool, which enables the identification any errors which occur in the production app (only if you enable it)."),(0,o.yg)("p",null,"To enable error reporting:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"appConfig:\n enableErrorReporting: true\n")),(0,o.yg)("p",null,"All reporting is ",(0,o.yg)("strong",{parentName:"p"},"disabled")," by default, and no data will ever be sent to any external endpoint without your explicit consent. All statistics are anonymized and stored securely. For more about privacy and security, see the ",(0,o.yg)("a",{parentName:"p",href:"https://sentry.io/security/"},"Sentry Security Docs"),"."),(0,o.yg)("h2",{id:"add-translations"},"Add Translations"),(0,o.yg)("p",null,"If you speak another language, then adding translations will help make Dashy available to non-native English speakers. This is a very quick and easy task, as all application text is located in ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/src/assets/locales/en.json"},(0,o.yg)("inlineCode",{parentName:"a"},"locales/en.json")),", so adding a new language is as simple as copying this file and translating the values. You don't have to translate it all, as any missing attributes will just fallback to English. For a full tutorial, see the ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/multi-language-support.md"},"Multi-Language Support Docs"),"."),(0,o.yg)("h2",{id:"submit-a-pr"},"Submit a PR"),(0,o.yg)("p",null,"Contributing to the code or docs is super helpful. You can fix a bug, add a new feature or improve an existing one. If you've built your own custom widget, theme or view, consider sharing it in a PR. I've written ",(0,o.yg)("a",{parentName:"p",href:"/docs/development-guides"},"several guides")," to help you get started, and the steps for setting up the development environment are outlined in the ",(0,o.yg)("a",{parentName:"p",href:"/docs/developing"},"Development Docs"),". Feel free to ask if you have any questions."),(0,o.yg)("h2",{id:"improve-the-docs"},"Improve the Docs"),(0,o.yg)("p",null,"Found a typo, or something that isn't as clear as it could be? Maybe I've missed something off altogether, or you hit a roadblock that took you a while to figure out. Submitting a pull request to add to or improve the documentation will help future users get Dashy up and running more easily.\nAll content is located either in the ",(0,o.yg)("a",{parentName:"p",href:"/README"},(0,o.yg)("inlineCode",{parentName:"a"},"./README.md"))," or ",(0,o.yg)("a",{parentName:"p",href:"/docs"},(0,o.yg)("inlineCode",{parentName:"a"},"/docs/"))," directory, and synced to the Wiki and website using a GH ",(0,o.yg)("a",{parentName:"p",href:"/actions/workflows/wiki-sync.yml"},"action"),"."),(0,o.yg)("h2",{id:"raise-a-bug"},"Raise a bug"),(0,o.yg)("p",null,"If you've found a bug, then please do raise it as an issue. This will help me know if there's something that needs fixing. Try and include as much detail as possible, such as your environment, steps to reproduce, any console output and maybe an example screenshot or recording if necessary."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/new?assignees=lissy93&labels=%F0%9F%90%9B+Bug&template=bug.yml&title=%5BBUG%5D+%3Ctitle%3E"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Raise_a-Bug-%23dc2d76?style=for-the-badge&logo=dependabot",alt:"Raise a Bug"}))),(0,o.yg)("h2",{id:"join-the-discussion"},"Join the discussion"),(0,o.yg)("p",null,"I've enabled the discussion feature on GitHub, here you can share tips and tricks, useful information, or your dashboard. You can also ask questions, and offer basic support to other users."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Join_the-Discussion-%23ffd000?style=for-the-badge&logo=livechat",alt:"Join the Discussion on GitHub"}))),(0,o.yg)("h2",{id:"request-a-feature-via-bountysource"},"Request a feature via BountySource"),(0,o.yg)("p",null,"BountySource is a platform for sponsoring the development of certain features on open source projects. If there is a feature you'd like implemented into Dashy, but either isn't high enough priority or is deemed to be more work than it's worth, then you can instead contribute a bounty towards it's development. You won't pay a penny until your proposal is fully built, and you are satisfied with the result. This helps support the developers, and makes Dashy better for everyone."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://www.bountysource.com/teams/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/BountySource-Dashy-%23F67909?style=for-the-badge&logo=openbugbounty",alt:"Request a Feature on BountySource"}))),(0,o.yg)("h2",{id:"spread-the-word"},"Spread the word"),(0,o.yg)("p",null,"Dashy is still a relatively young project, and as such not many people know of it. It would be great to see more users, and so it would be awesome if you could consider sharing with your friends or on social platforms."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://mastodon.social/?text=Check%20out%20Dashy%2C%20the%20privacy-friendly%2C%20self-hosted%20startpage%20for%20organizing%20your%20life%3A%20https%3A%2F%2Fgithub.com%2FLissy93%2Fdashy%20-%20By%20%40lissy93%40mastodon.social"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Mastodon-%232b90d9?style=flat-square&logo=mastodon",alt:"Share Dashy on Mastodon"})),"\n",(0,o.yg)("a",{parentName:"p",href:"http://www.reddit.com/submit?url=https://github.com/Lissy93/dashy&title=Dashy%20-%20The%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Reddit-%23FF5700?style=flat-square&logo=reddit",alt:"Share Dashy on Reddit"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://twitter.com/intent/tweet?url=https://github.com/lissy93/dashy&text=Check%20out%20Dashy%20by%20@Lissy_Sykes,%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Twitter-%231DA1F2?style=flat-square&logo=twitter",alt:"Share Dashy on Twitter"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://www.facebook.com/sharer/sharer.php?u=https://github.com/lissy93/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Facebook-%234267B2?style=flat-square&logo=facebook",alt:"Share Dashy on Facebook"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/lissy93/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-LinkedIn-%230077b5?style=flat-square&logo=linkedin",alt:"Share Dashy on LinkedIn"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://pinterest.com/pin/create/button/?url=https://github.com/lissy93/dashy&media=https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/1-home-lab-material.png&description=Check%20out%20Dashy,%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Pinterest-%23E60023?style=flat-square&logo=pinterest",alt:"Share Dashy on Pinterest"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://vk.com/share.php?url=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy%2F&title=Check%20out%20Dashy%20-%20The%20Self-Hosted%20Dashboard%20for%20your%20Homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-VK-%234C75A3?style=flat-square&logo=vk",alt:"Share Dashy on VK"})),"\n",(0,o.yg)("a",{parentName:"p",href:"viber://forward?text=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy%0ACheck%20out%20Dashy%2C%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Viber-%238176d6?style=flat-square&logo=viber",alt:"Share Dashy via Viber"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://t.me/share/url?url=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy&text=Check%20out%20Dashy%2C%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Telegram-%230088cc?style=flat-square&logo=telegram",alt:"Share Dashy via Telegram"})),"\n",(0,o.yg)("a",{parentName:"p",href:"mailto:info@example.com?&subject=Check%20out%20Dashy%20-%20The%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80&cc=&bcc=&body=https://github.com/lissy93/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Email-%238A90C7?style=flat-square&logo=protonmail",alt:"Share Dashy via Email"}))),(0,o.yg)("h2",{id:"star-upvote-or-leave-a-review"},"Star, Upvote or Leave a Review"),(0,o.yg)("p",null,"Dashy is on the following platforms, and if you could spare a few seconds to give it an upvote or review, this will also help new users discover Dashy"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://www.producthunt.com/posts/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Review-ProductHunt-%23b74424?style=flat-square&logo=producthunt",alt:"ProductHunt"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://alternativeto.net/software/dashy/about/"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Review-AlternativeTo-%235581a6?style=flat-square&logo=abletonlive",alt:"AlternativeTo"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://www.slant.co/improve/topics/27783/viewpoints/1/~self-hosted-homelab-startpage~dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Review-Slant-%2346a1df?style=flat-square&logo=capacitor",alt:"Slant"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/stargazers"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/github/stars/Lissy93/Dashy?color=ba96d6&label=Star%20-%20GitHub&logo=github&style=flat-square",alt:"Star on GitHub"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://hub.docker.com/r/lissy93/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/docker/stars/lissy93/dashy?color=4cb6e0&label=Star%20-%20Docker&logo=docker&style=flat-square",alt:"Star on DockerHub"}))),(0,o.yg)("h2",{id:"follow-for-more"},"Follow for More"),(0,o.yg)("p",null,"If you've enjoyed Dashy, you can follow the me to get updates about other projects that I am working on."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://twitter.com/Lissy_Sykes"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/twitter/follow/Lissy_Sykes?style=social&logo=twitter",alt:"Alicia Sykes on Twitter"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/github/followers/lissy93?label=Lissy93&style=social",alt:"Alicia Sykes on GitHub"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://mastodon.social/web/accounts/1032965"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/mastodon/follow/1032965?domain=https%3A%2F%2Fmastodon.social",alt:"Alicia Sykes on Mastodon"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://keybase.io/aliciasykes"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/aliciasykes--lightgrey?style=social&logo=Keybase",alt:"Alicia Sykes on Keybase"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://aliciasykes.com"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/aliciasykes.com--lightgrey?style=social&logo=Tencent%20QQ",alt:"Alicia Sykes's Website"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://notes.aliciasykes.com/"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Blog--lightgrey?style=social&logo=micro.blog",alt:"Alicia Sykes's Blog"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://keybase.io/aliciasykes/pgp_keys.asc"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/PGP--lightgrey?style=social&logo=Let%E2%80%99s%20Encrypt",alt:"Alicia Sykes's PGP"}))),(0,o.yg)("p",null,"If you like, you could also consider ",(0,o.yg)("a",{parentName:"p",href:"https://notes.aliciasykes.com/subscribe"},"subscribing to my mailing list")," for occasional blog post updates."),(0,o.yg)("hr",null),(0,o.yg)("h3",{id:"contributors"},"Contributors"),(0,o.yg)("p",null,"For a full list of Dashy's contributors, see the ",(0,o.yg)("a",{parentName:"p",href:"/docs/credits"},"Credits Page")),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"/docs/credits"},(0,o.yg)("img",{parentName:"a",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/CONTRIBUTORS.svg",alt:"Auto-generated contributors"}))),(0,o.yg)("h3",{id:"star-gazers-over-time"},"Star-Gazers Over Time"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://seladb.github.io/StarTrack-js/#/preload?r=Lissy93,dashy"},(0,o.yg)("img",{parentName:"a",src:"https://starchart.cc/Lissy93/dashy.svg",alt:"Stargazers"}))))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[459],{5680:(e,t,a)=>{a.d(t,{xA:()=>y,yg:()=>g});var s=a(6540);function o(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,s)}return a}function i(e){for(var t=1;t=0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(s=0;s=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(o[a]=e[a])}return o}var l=s.createContext({}),h=function(e){var t=s.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},y=function(e){var t=h(e.components);return s.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return s.createElement(s.Fragment,{},t)}},d=s.forwardRef((function(e,t){var a=e.components,o=e.mdxType,r=e.originalType,l=e.parentName,y=n(e,["components","mdxType","originalType","parentName"]),p=h(a),d=o,g=p["".concat(l,".").concat(d)]||p[d]||u[d]||r;return a?s.createElement(g,i(i({ref:t},y),{},{components:a})):s.createElement(g,i({ref:t},y))}));function g(e,t){var a=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=a.length,i=new Array(r);i[0]=d;var n={};for(var l in t)hasOwnProperty.call(t,l)&&(n[l]=t[l]);n.originalType=e,n[p]="string"==typeof e?e:o,i[1]=n;for(var h=2;h{a.r(t),a.d(t,{contentTitle:()=>i,default:()=>p,frontMatter:()=>r,metadata:()=>n,toc:()=>l});var s=a(8168),o=(a(6540),a(5680));const r={},i="Contributing",n={unversionedId:"contributing",id:"contributing",isDocsHomePage:!1,title:"Contributing",description:"First off, thank you for considering contributing towards Dashy! \ud83d\ude4c",source:"@site/docs/contributing.md",sourceDirName:".",slug:"/contributing",permalink:"/docs/contributing",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/contributing.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"*Dashy Showcase* \ud83c\udf1f",permalink:"/docs/showcase"},next:{title:"Developing",permalink:"/docs/developing"}},l=[{value:"Take a 2-minute survey",id:"take-a-2-minute-survey",children:[]},{value:"Share your dashboard",id:"share-your-dashboard",children:[]},{value:"Make a small donation",id:"make-a-small-donation",children:[]},{value:"Enable Anonymous Bug Reports",id:"enable-anonymous-bug-reports",children:[]},{value:"Add Translations",id:"add-translations",children:[]},{value:"Submit a PR",id:"submit-a-pr",children:[]},{value:"Improve the Docs",id:"improve-the-docs",children:[]},{value:"Raise a bug",id:"raise-a-bug",children:[]},{value:"Join the discussion",id:"join-the-discussion",children:[]},{value:"Request a feature via BountySource",id:"request-a-feature-via-bountysource",children:[]},{value:"Spread the word",id:"spread-the-word",children:[]},{value:"Star, Upvote or Leave a Review",id:"star-upvote-or-leave-a-review",children:[]},{value:"Follow for More",id:"follow-for-more",children:[{value:"Contributors",id:"contributors",children:[]},{value:"Star-Gazers Over Time",id:"star-gazers-over-time",children:[]}]}],h={toc:l},y="wrapper";function p(e){let{components:t,...a}=e;return(0,o.yg)(y,(0,s.A)({},h,a,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"contributing"},"Contributing"),(0,o.yg)("p",null,"First off, thank you for considering contributing towards Dashy! \ud83d\ude4c\nThere are several ways that you can help out, and any contributions, however small will always be very much appreciated.\nYou will be appropriately credited in the readme - huge thank you to ",(0,o.yg)("a",{parentName:"p",href:"/docs/credits"},"everyone who has helped")," so far \ud83d\udc9e"),(0,o.yg)("h2",{id:"take-a-2-minute-survey"},"Take a 2-minute survey"),(0,o.yg)("p",null,"Help improve Dashy by taking a very short, 6-question survey. This will give me a better understanding of what is important to you, so that I can make Dashy better in the future :)"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://survey.typeform.com/to/gl0L68ou"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Take_the-Survey-%231a86fd?style=for-the-badge&logo=buddy",alt:"Take the Survey"}))),(0,o.yg)("h2",{id:"share-your-dashboard"},"Share your dashboard"),(0,o.yg)("p",null,"Dashy now has a ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/showcase.md#dashy-showcase-"},"Showcase")," where you can show off a screenshot of your dashboard, and get inspiration from other users (and I really love seeing how people are using Dashy). To ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/showcase.md#submitting-your-dashboard"},"submit your dashboard"),", either open a PR or raise an issue."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/new?assignees=&labels=%F0%9F%92%AF+Showcase&template=showcase-addition.yml&title=%5BSHOWCASE%5D+%3Ctitle%3E"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Add_your_Dashboard-Showcase-%238616ee?style=for-the-badge&logo=feathub&logoColor=8616ee",alt:"Add your Dashboard to the Showcase"}))),(0,o.yg)("h2",{id:"make-a-small-donation"},"Make a small donation"),(0,o.yg)("p",null,"Donations help to cover server costs, development time and caffeine ;)\nDon't feel any pressure to donate anything, as Dashy and my other projects will always be 100% free, for everyone, for ever."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/sponsors/Lissy93"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Sponsor_on_GitHub-Lissy93-%23ff4dda?style=for-the-badge&logo=githubsponsors&logoColor=ff4dda",alt:"Sponsor Lissy93 on GitHub"}))),(0,o.yg)("p",null,"Sponsoring will give you several perks - for $1 / \xa30.75 per month, you'll get a sponsor badge on your profile, be credited on the Dashy's readme, with a link to your website/ profile/ socials, get priority support, have your feature ideas implemented, plus lots more. For more info, see ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/sponsors/Lissy93"},"@Lissy93's Sponsor Page"),"."),(0,o.yg)("h2",{id:"enable-anonymous-bug-reports"},"Enable Anonymous Bug Reports"),(0,o.yg)("p",null,"Bug reports helps me to discover bugs I was unaware of, and then fix them, in order to make Dashy more reliable long term. This is a simple, yet really helpful step you can take to help improve Dashy. ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/getsentry/sentry"},"Sentry")," is an open source error tracking and performance monitoring tool, which enables the identification any errors which occur in the production app (only if you enable it)."),(0,o.yg)("p",null,"To enable error reporting:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"appConfig:\n enableErrorReporting: true\n")),(0,o.yg)("p",null,"All reporting is ",(0,o.yg)("strong",{parentName:"p"},"disabled")," by default, and no data will ever be sent to any external endpoint without your explicit consent. All statistics are anonymized and stored securely. For more about privacy and security, see the ",(0,o.yg)("a",{parentName:"p",href:"https://sentry.io/security/"},"Sentry Security Docs"),"."),(0,o.yg)("h2",{id:"add-translations"},"Add Translations"),(0,o.yg)("p",null,"If you speak another language, then adding translations will help make Dashy available to non-native English speakers. This is a very quick and easy task, as all application text is located in ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/src/assets/locales/en.json"},(0,o.yg)("inlineCode",{parentName:"a"},"locales/en.json")),", so adding a new language is as simple as copying this file and translating the values. You don't have to translate it all, as any missing attributes will just fallback to English. For a full tutorial, see the ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/multi-language-support.md"},"Multi-Language Support Docs"),"."),(0,o.yg)("h2",{id:"submit-a-pr"},"Submit a PR"),(0,o.yg)("p",null,"Contributing to the code or docs is super helpful. You can fix a bug, add a new feature or improve an existing one. If you've built your own custom widget, theme or view, consider sharing it in a PR. I've written ",(0,o.yg)("a",{parentName:"p",href:"/docs/development-guides"},"several guides")," to help you get started, and the steps for setting up the development environment are outlined in the ",(0,o.yg)("a",{parentName:"p",href:"/docs/developing"},"Development Docs"),". Feel free to ask if you have any questions."),(0,o.yg)("h2",{id:"improve-the-docs"},"Improve the Docs"),(0,o.yg)("p",null,"Found a typo, or something that isn't as clear as it could be? Maybe I've missed something off altogether, or you hit a roadblock that took you a while to figure out. Submitting a pull request to add to or improve the documentation will help future users get Dashy up and running more easily.\nAll content is located either in the ",(0,o.yg)("a",{parentName:"p",href:"/README"},(0,o.yg)("inlineCode",{parentName:"a"},"./README.md"))," or ",(0,o.yg)("a",{parentName:"p",href:"/docs"},(0,o.yg)("inlineCode",{parentName:"a"},"/docs/"))," directory, and synced to the Wiki and website using a GH ",(0,o.yg)("a",{parentName:"p",href:"/actions/workflows/wiki-sync.yml"},"action"),"."),(0,o.yg)("h2",{id:"raise-a-bug"},"Raise a bug"),(0,o.yg)("p",null,"If you've found a bug, then please do raise it as an issue. This will help me know if there's something that needs fixing. Try and include as much detail as possible, such as your environment, steps to reproduce, any console output and maybe an example screenshot or recording if necessary."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/new?assignees=lissy93&labels=%F0%9F%90%9B+Bug&template=bug.yml&title=%5BBUG%5D+%3Ctitle%3E"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Raise_a-Bug-%23dc2d76?style=for-the-badge&logo=dependabot",alt:"Raise a Bug"}))),(0,o.yg)("h2",{id:"join-the-discussion"},"Join the discussion"),(0,o.yg)("p",null,"I've enabled the discussion feature on GitHub, here you can share tips and tricks, useful information, or your dashboard. You can also ask questions, and offer basic support to other users."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/discussions"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Join_the-Discussion-%23ffd000?style=for-the-badge&logo=livechat",alt:"Join the Discussion on GitHub"}))),(0,o.yg)("h2",{id:"request-a-feature-via-bountysource"},"Request a feature via BountySource"),(0,o.yg)("p",null,"BountySource is a platform for sponsoring the development of certain features on open source projects. If there is a feature you'd like implemented into Dashy, but either isn't high enough priority or is deemed to be more work than it's worth, then you can instead contribute a bounty towards it's development. You won't pay a penny until your proposal is fully built, and you are satisfied with the result. This helps support the developers, and makes Dashy better for everyone."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://www.bountysource.com/teams/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/BountySource-Dashy-%23F67909?style=for-the-badge&logo=openbugbounty",alt:"Request a Feature on BountySource"}))),(0,o.yg)("h2",{id:"spread-the-word"},"Spread the word"),(0,o.yg)("p",null,"Dashy is still a relatively young project, and as such not many people know of it. It would be great to see more users, and so it would be awesome if you could consider sharing with your friends or on social platforms."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://mastodon.social/?text=Check%20out%20Dashy%2C%20the%20privacy-friendly%2C%20self-hosted%20startpage%20for%20organizing%20your%20life%3A%20https%3A%2F%2Fgithub.com%2FLissy93%2Fdashy%20-%20By%20%40lissy93%40mastodon.social"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Mastodon-%232b90d9?style=flat-square&logo=mastodon",alt:"Share Dashy on Mastodon"})),"\n",(0,o.yg)("a",{parentName:"p",href:"http://www.reddit.com/submit?url=https://github.com/Lissy93/dashy&title=Dashy%20-%20The%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Reddit-%23FF5700?style=flat-square&logo=reddit",alt:"Share Dashy on Reddit"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://twitter.com/intent/tweet?url=https://github.com/lissy93/dashy&text=Check%20out%20Dashy%20by%20@Lissy_Sykes,%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Twitter-%231DA1F2?style=flat-square&logo=twitter",alt:"Share Dashy on Twitter"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://www.facebook.com/sharer/sharer.php?u=https://github.com/lissy93/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Facebook-%234267B2?style=flat-square&logo=facebook",alt:"Share Dashy on Facebook"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/lissy93/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-LinkedIn-%230077b5?style=flat-square&logo=linkedin",alt:"Share Dashy on LinkedIn"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://pinterest.com/pin/create/button/?url=https://github.com/lissy93/dashy&media=https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/1-home-lab-material.png&description=Check%20out%20Dashy,%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Pinterest-%23E60023?style=flat-square&logo=pinterest",alt:"Share Dashy on Pinterest"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://vk.com/share.php?url=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy%2F&title=Check%20out%20Dashy%20-%20The%20Self-Hosted%20Dashboard%20for%20your%20Homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-VK-%234C75A3?style=flat-square&logo=vk",alt:"Share Dashy on VK"})),"\n",(0,o.yg)("a",{parentName:"p",href:"viber://forward?text=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy%0ACheck%20out%20Dashy%2C%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Viber-%238176d6?style=flat-square&logo=viber",alt:"Share Dashy via Viber"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://t.me/share/url?url=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy&text=Check%20out%20Dashy%2C%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Telegram-%230088cc?style=flat-square&logo=telegram",alt:"Share Dashy via Telegram"})),"\n",(0,o.yg)("a",{parentName:"p",href:"mailto:info@example.com?&subject=Check%20out%20Dashy%20-%20The%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80&cc=&bcc=&body=https://github.com/lissy93/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Share-Email-%238A90C7?style=flat-square&logo=protonmail",alt:"Share Dashy via Email"}))),(0,o.yg)("h2",{id:"star-upvote-or-leave-a-review"},"Star, Upvote or Leave a Review"),(0,o.yg)("p",null,"Dashy is on the following platforms, and if you could spare a few seconds to give it an upvote or review, this will also help new users discover Dashy"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://www.producthunt.com/posts/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Review-ProductHunt-%23b74424?style=flat-square&logo=producthunt",alt:"ProductHunt"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://alternativeto.net/software/dashy/about/"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Review-AlternativeTo-%235581a6?style=flat-square&logo=abletonlive",alt:"AlternativeTo"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://www.slant.co/improve/topics/27783/viewpoints/1/~self-hosted-homelab-startpage~dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Review-Slant-%2346a1df?style=flat-square&logo=capacitor",alt:"Slant"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/stargazers"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/github/stars/Lissy93/Dashy?color=ba96d6&label=Star%20-%20GitHub&logo=github&style=flat-square",alt:"Star on GitHub"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://hub.docker.com/r/lissy93/dashy"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/docker/stars/lissy93/dashy?color=4cb6e0&label=Star%20-%20Docker&logo=docker&style=flat-square",alt:"Star on DockerHub"}))),(0,o.yg)("h2",{id:"follow-for-more"},"Follow for More"),(0,o.yg)("p",null,"If you've enjoyed Dashy, you can follow the me to get updates about other projects that I am working on."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://twitter.com/Lissy_Sykes"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/twitter/follow/Lissy_Sykes?style=social&logo=twitter",alt:"Alicia Sykes on Twitter"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/github/followers/lissy93?label=Lissy93&style=social",alt:"Alicia Sykes on GitHub"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://mastodon.social/web/accounts/1032965"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/mastodon/follow/1032965?domain=https%3A%2F%2Fmastodon.social",alt:"Alicia Sykes on Mastodon"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://keybase.io/aliciasykes"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/aliciasykes--lightgrey?style=social&logo=Keybase",alt:"Alicia Sykes on Keybase"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://aliciasykes.com"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/aliciasykes.com--lightgrey?style=social&logo=Tencent%20QQ",alt:"Alicia Sykes's Website"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://notes.aliciasykes.com/"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/Blog--lightgrey?style=social&logo=micro.blog",alt:"Alicia Sykes's Blog"})),"\n",(0,o.yg)("a",{parentName:"p",href:"https://keybase.io/aliciasykes/pgp_keys.asc"},(0,o.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/PGP--lightgrey?style=social&logo=Let%E2%80%99s%20Encrypt",alt:"Alicia Sykes's PGP"}))),(0,o.yg)("p",null,"If you like, you could also consider ",(0,o.yg)("a",{parentName:"p",href:"https://notes.aliciasykes.com/subscribe"},"subscribing to my mailing list")," for occasional blog post updates."),(0,o.yg)("hr",null),(0,o.yg)("h3",{id:"contributors"},"Contributors"),(0,o.yg)("p",null,"For a full list of Dashy's contributors, see the ",(0,o.yg)("a",{parentName:"p",href:"/docs/credits"},"Credits Page")),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/credits.md"},(0,o.yg)("img",{parentName:"a",src:"https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/CONTRIBUTORS.svg",alt:"Auto-generated contributors"}))),(0,o.yg)("h3",{id:"star-gazers-over-time"},"Star-Gazers Over Time"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://seladb.github.io/StarTrack-js/#/preload?r=Lissy93,dashy"},(0,o.yg)("img",{parentName:"a",src:"https://starchart.cc/Lissy93/dashy.svg",alt:"Stargazers"}))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/625b1ed7.57bbcc5e.js b/assets/js/625b1ed7.57bbcc5e.js deleted file mode 100644 index 4f72b66b..00000000 --- a/assets/js/625b1ed7.57bbcc5e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[831],{5680:(e,a,t)=>{t.d(a,{xA:()=>p,yg:()=>y});var n=t(6540);function o(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function i(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function r(e){for(var a=1;a=0||(o[t]=e[t]);return o}(e,a);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=n.createContext({}),c=function(e){var a=n.useContext(l),t=a;return e&&(t="function"==typeof e?e(a):r(r({},a),e)),t},p=function(e){var a=c(e.components);return n.createElement(l.Provider,{value:a},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},d=n.forwardRef((function(e,a){var t=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(t),d=o,y=u["".concat(l,".").concat(d)]||u[d]||h[d]||i;return t?n.createElement(y,r(r({ref:a},p),{},{components:t})):n.createElement(y,r({ref:a},p))}));function y(e,a){var t=arguments,o=a&&a.mdxType;if("string"==typeof e||o){var i=t.length,r=new Array(i);r[0]=d;var s={};for(var l in a)hasOwnProperty.call(a,l)&&(s[l]=a[l]);s.originalType=e,s[u]="string"==typeof e?e:o,r[1]=s;for(var c=2;c{t.r(a),t.d(a,{contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var n=t(8168),o=(t(6540),t(5680));const i={},r="Authentication",s={unversionedId:"authentication",id:"authentication",isDocsHomePage:!1,title:"Authentication",description:"- Basic Auth",source:"@site/docs/authentication.md",sourceDirName:".",slug:"/authentication",permalink:"/docs/authentication",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/authentication.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Status Indicators",permalink:"/docs/status-indicators"},next:{title:"Keyboard Shortcuts",permalink:"/docs/searching"}},l=[{value:"Built-In Auth",id:"built-in-auth",children:[{value:"Setting Up Authentication",id:"setting-up-authentication",children:[]},{value:"Hash Password",id:"hash-password",children:[]},{value:"Logging In and Out",id:"logging-in-and-out",children:[]},{value:"Enabling Guest Access",id:"enabling-guest-access",children:[]},{value:"Granular Access",id:"granular-access",children:[]},{value:"Permissions",id:"permissions",children:[]},{value:"Security",id:"security",children:[]}]},{value:"Keycloak",id:"keycloak",children:[{value:"1. Deploy Keycloak",id:"1-deploy-keycloak",children:[]},{value:"2. Setup Keycloak Users",id:"2-setup-keycloak-users",children:[]},{value:"3. Enable Keycloak in Dashy Config File",id:"3-enable-keycloak-in-dashy-config-file",children:[]},{value:"4. Add groups and roles (Optional)",id:"4-add-groups-and-roles-optional",children:[]}]},{value:"Alternative Authentication Methods",id:"alternative-authentication-methods",children:[{value:"Authentication Server",id:"authentication-server",children:[]},{value:"VPN",id:"vpn",children:[]},{value:"IP-Based Access",id:"ip-based-access",children:[]},{value:"Web Server Authentication",id:"web-server-authentication",children:[]},{value:"OAuth Services",id:"oauth-services",children:[]},{value:"Static Site Hosting Providers",id:"static-site-hosting-providers",children:[]}]}],c={toc:l},p="wrapper";function u(e){let{components:a,...t}=e;return(0,o.yg)(p,(0,n.A)({},c,t,{components:a,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"authentication"},"Authentication"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#built-in-auth"},"Basic Auth"),(0,o.yg)("ul",{parentName:"li"},(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#setting-up-authentication"},"Setting Up Authentication")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#hash-password"},"Hash Password")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#logging-in-and-out"},"Logging In and Out")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#enabling-guest-access"},"Guest Access")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#granular-access"},"Per-User Access")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#security"},"Security Considerations")))),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#keycloak"},"Keycloak Auth"),(0,o.yg)("ul",{parentName:"li"},(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#1-deploy-keycloak"},"Deploying Keycloak")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#2-setup-keycloak-users"},"Setting up Keycloak")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#3-enable-keycloak-in-dashy-config-file"},"Configuring Dashy for Keycloak")))),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#alternative-authentication-methods"},"Alternative Authentication Methods"),(0,o.yg)("ul",{parentName:"li"},(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#vpn"},"VPN")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#ip-based-access"},"IP-Based Access")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#web-server-authentication"},"Web Server Authentication")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#oauth-services"},"OAuth Services")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#static-site-hosting-providers"},"Auth on Cloud Hosting Services"))))),(0,o.yg)("blockquote",null,(0,o.yg)("p",{parentName:"blockquote"},"[!IMPORTANT]","\nDashy's built-in auth is not indented to protect a publicly hosted instance against unauthorized access. Instead you should use an auth provider compatible with your reverse proxy, or access Dashy via your VPN. "),(0,o.yg)("p",{parentName:"blockquote"},"In cases where Dashy is only accessibly within your home network, and you just want to add a login page, then the built-in auth may be sufficient, but keep in mind that configuration can still be accessed.")),(0,o.yg)("h2",{id:"built-in-auth"},"Built-In Auth"),(0,o.yg)("p",null,"Dashy has a basic login page included, and frontend authentication. You can enable this by adding users to the ",(0,o.yg)("inlineCode",{parentName:"p"},"auth")," section under ",(0,o.yg)("inlineCode",{parentName:"p"},"appConfig")," in your ",(0,o.yg)("inlineCode",{parentName:"p"},"conf.yml"),". If this section is not specified, then no authentication will be required to access the app, and the homepage will resolve to your dashboard."),(0,o.yg)("h3",{id:"setting-up-authentication"},"Setting Up Authentication"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"auth")," property takes an array of users. Each user needs to include a username, hash and optional user type (",(0,o.yg)("inlineCode",{parentName:"p"},"admin")," or ",(0,o.yg)("inlineCode",{parentName:"p"},"normal"),"). The hash property is a ",(0,o.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/SHA-2"},"SHA-256 Hash")," of your desired password."),(0,o.yg)("p",null,"For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"appConfig:\n auth:\n users:\n - user: alicia\n hash: 4D1E58C90B3B94BCAD9848ECCACD6D2A8C9FBC5CA913304BBA5CDEAB36FEEFA3\n type: admin\n - user: bob\n hash: 5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8\n")),(0,o.yg)("h3",{id:"hash-password"},"Hash Password"),(0,o.yg)("p",null,"Dashy uses ",(0,o.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Sha-256"},"SHA-256 Hash"),", a 64-character string, which you can generate using an online tool, such as ",(0,o.yg)("a",{parentName:"p",href:"https://passwordsgenerator.net/sha256-hash-generator/"},"this one")," or ",(0,o.yg)("a",{parentName:"p",href:"https://gchq.github.io/CyberChef/"},"CyberChef")," (which can be self-hosted/ ran locally)."),(0,o.yg)("p",null,"A hash is a one-way cryptographic function, meaning that it is easy to generate a hash for a given password, but very hard to determine the original password for a given hash. This means, that so long as your password is long, strong and unique, it is safe to store its hash in the clear. Having said that, you should never reuse passwords, hashes can be cracked by iterating over known password lists, generating a hash of each."),(0,o.yg)("h3",{id:"logging-in-and-out"},"Logging In and Out"),(0,o.yg)("p",null,"Once authentication is enabled, so long as there is no valid token in cookie storage, the application will redirect the user to the login page. When the user enters credentials in the login page, they will be checked, and if valid, then a token will be generated, and they can be redirected to the home page. If credentials are invalid, then an error message will be shown, and they will remain on the login page. Once in the application, to log out: the user can click the logout button (in the top-right), which will clear cookie storage, causing them to be redirected back to the login page."),(0,o.yg)("h3",{id:"enabling-guest-access"},"Enabling Guest Access"),(0,o.yg)("p",null,"With authentication set up, by default no access is allowed to your dashboard without first logging in with valid credentials. Guest mode can be enabled to allow for read-only access to a secured dashboard by any user, without the need to log in. A guest user cannot write any changes to the config file, but can apply modifications locally (stored in their browser). You can enable guest access, by setting ",(0,o.yg)("inlineCode",{parentName:"p"},"appConfig.auth.enableGuestAccess: true"),"."),(0,o.yg)("h3",{id:"granular-access"},"Granular Access"),(0,o.yg)("p",null,"You can use the following properties to make certain pages, sections or items only visible to some users, or hide pages, sections and items from guests."),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"hideForUsers")," - Page, Section or Item will be visible to all users, except for those specified in this list"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"showForUsers")," - Page, Section or Item will be hidden from all users, except for those specified in this list"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"hideForGuests")," - Page, Section or Item will be visible for logged in users, but not for guests")),(0,o.yg)("p",null,"For Example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"pages:\n - name: Home Lab\n path: home-lab.yml\n displayData:\n showForUsers: [admin]\n - name: Intranet\n path: intranet.yml\n displayData:\n hideForGuests: true\n hideForUsers: [alicia, bob]\n")),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"- name: Code Analysis & Monitoring\n icon: fas fa-code\n displayData:\n cols: 2\n hideForUsers: [alicia, bob]\n items:\n ...\n")),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"- name: Deployment Pipelines\n icon: fas fa-rocket\n displayData:\n hideForGuests: true\n items:\n - title: Hide Me\n displayData:\n hideForUsers: [alicia, bob]\n")),(0,o.yg)("h3",{id:"permissions"},"Permissions"),(0,o.yg)("p",null,"Any user who is not an admin (with ",(0,o.yg)("inlineCode",{parentName:"p"},"type: admin"),") will not be able to write changes to disk."),(0,o.yg)("p",null,"You can also prevent any user from writing changes to disk, using ",(0,o.yg)("inlineCode",{parentName:"p"},"preventWriteToDisk"),". Or prevent any changes from being saved locally in browser storage, using ",(0,o.yg)("inlineCode",{parentName:"p"},"preventLocalSave"),". Both properties can be found under ",(0,o.yg)("a",{parentName:"p",href:"/docs/configuring#appconfig-optional"},(0,o.yg)("inlineCode",{parentName:"a"},"appConfig")),"."),(0,o.yg)("p",null,"To disable all UI config features, including View Config, set ",(0,o.yg)("inlineCode",{parentName:"p"},"disableConfiguration"),". Alternatively you can disable UI config features for all non admin users by setting ",(0,o.yg)("inlineCode",{parentName:"p"},"disableConfigurationForNonAdmin")," to true."),(0,o.yg)("h3",{id:"security"},"Security"),(0,o.yg)("p",null,"With basic auth, all logic is happening on the client-side, which could mean a skilled user could manipulate the code to view parts of your configuration, including the hash. If the SHA-256 hash is of a common password, it may be possible to determine it, using a lookup table, in order to find the original password. Which can be used to manually generate the auth token, that can then be inserted into session storage, to become a valid logged in user. Therefore, you should always use a long, strong and unique password, and if you instance contains security-critical info and/ or is exposed directly to the internet, and alternative authentication method may be better. The purpose of the login page is merely to prevent immediate unauthorized access to your homepage."),(0,o.yg)("p",null,(0,o.yg)("strong",{parentName:"p"},(0,o.yg)("a",{parentName:"strong",href:"#authentication"},"\u2b06\ufe0f Back to Top"))),(0,o.yg)("hr",null),(0,o.yg)("h2",{id:"keycloak"},"Keycloak"),(0,o.yg)("p",null,"Dashy also supports using a ",(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/"},"Keycloak")," authentication server. The setup for this is a bit more involved, but it gives you greater security overall, useful for if your instance is exposed to the internet."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/about.html"},"Keycloak")," is a Java-based ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/keycloak/keycloak"},"open source"),", high-performance, secure authentication system, supported by ",(0,o.yg)("a",{parentName:"p",href:"https://www.redhat.com/en"},"RedHat"),". It is easy to setup (",(0,o.yg)("a",{parentName:"p",href:"https://quay.io/repository/keycloak/keycloak"},"with Docker"),"), and enables you to secure multiple self-hosted applications with single-sign-on using standard protocols (OpenID Connect, OAuth 2.0, SAML 2.0 and social login). It's also very customizable, you can write or use custom ",(0,o.yg)("a",{parentName:"p",href:"https://wjw465150.gitbooks.io/keycloak-documentation/content/server_development/topics/themes.html"},"themes"),", ",(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/extensions.html"},"plugins"),", ",(0,o.yg)("a",{parentName:"p",href:"https://wjw465150.gitbooks.io/keycloak-documentation/content/server_admin/topics/authentication/password-policies.html"},"password policies")," and more.\nThe following guide will walk you through setting up Keycloak with Dashy. If you already have a Keycloak instance configured, then skip to Step 3."),(0,o.yg)("h3",{id:"1-deploy-keycloak"},"1. Deploy Keycloak"),(0,o.yg)("p",null,"First thing to do is to spin up a new instance of Keycloak. You will need ",(0,o.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/install/"},"Docker installed"),", and can then choose a tag, and pull the container from ",(0,o.yg)("a",{parentName:"p",href:"https://quay.io/repository/keycloak/keycloak"},"quay.io/keycloak/keycloak")),(0,o.yg)("p",null,"Use the following run command, replacing the attributes (default credentials, port and name), or incorporate this into your docker-compose file."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n -p 8081:8080 \\\n --name auth-server \\\n -e KEYCLOAK_USER=admin \\\n -e KEYCLOAK_PASSWORD=admin \\\n quay.io/keycloak/keycloak:15.0.2\n")),(0,o.yg)("p",null,"If you need to pull from DockerHub, a non-official image is available ",(0,o.yg)("a",{parentName:"p",href:"https://registry.hub.docker.com/r/jboss/keycloak"},"here"),". Or if you would prefer not to use Docker, you can also directly install Keycloak from source, following ",(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/docs/latest/getting_started/index.html"},"this guide"),"."),(0,o.yg)("p",null,"You should now be able to access the Keycloak web interface, using the port specified above (e.g. ",(0,o.yg)("inlineCode",{parentName:"p"},"http://127.0.0.1:8081"),"), login with the default credentials, and when prompted create a new password."),(0,o.yg)("h3",{id:"2-setup-keycloak-users"},"2. Setup Keycloak Users"),(0,o.yg)("p",null,"Before we can use Keycloak, we must first set it up with some users. Keycloak uses Realms (similar to tenants) to create isolated groups of users. You must create a Realm before you will be able to add your first user."),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"Head over to the admin console"),(0,o.yg)("li",{parentName:"ol"},"In the top-left corner there is a dropdown called 'Master', hover over it and then click 'Add Realm'"),(0,o.yg)("li",{parentName:"ol"},"Give your realm a name, and hit 'Create'")),(0,o.yg)("p",null,"You can now create your first user."),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"In the left-hand menu, click 'Users', then 'Add User'"),(0,o.yg)("li",{parentName:"ol"},"Fill in the form, including username and hit 'Save'"),(0,o.yg)("li",{parentName:"ol"},"Under the 'Credentials' tab, give the new user an initial password. They will be prompted to change this after first login")),(0,o.yg)("p",null,"The last thing we need to do in the Keycloak admin console is to create a new client"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"Within your new realm, navigate to 'Clients' on the left-hand side, then click 'Create' in the top-right"),(0,o.yg)("li",{parentName:"ol"},"Choose a 'Client ID', set 'Client Protocol' to 'openid-connect', and for 'Valid Redirect URIs' put a URL pattern to where you're hosting Dashy (if you're just testing locally, then * is fine), and do the same for the 'Web Origins' field"),(0,o.yg)("li",{parentName:"ol"},"Make note of your client-id, and click 'Save'")),(0,o.yg)("h3",{id:"3-enable-keycloak-in-dashy-config-file"},"3. Enable Keycloak in Dashy Config File"),(0,o.yg)("p",null,"Now that your Keycloak instance is up and running, all that's left to do is to configure Dashy to use it. Under ",(0,o.yg)("inlineCode",{parentName:"p"},"appConfig"),", set ",(0,o.yg)("inlineCode",{parentName:"p"},"auth.enableKeycloak: true"),", then fill in the details in ",(0,o.yg)("inlineCode",{parentName:"p"},"auth.keycloak"),", including: ",(0,o.yg)("inlineCode",{parentName:"p"},"serverUrl")," - the URL where your Keycloak instance is hosted, ",(0,o.yg)("inlineCode",{parentName:"p"},"realm")," - the name you gave your Realm, and ",(0,o.yg)("inlineCode",{parentName:"p"},"clientId")," - the Client ID you chose.\nFor example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"appConfig:\n ...\n auth:\n enableKeycloak: true\n keycloak:\n serverUrl: 'http://localhost:8081'\n realm: 'alicia-homelab'\n clientId: 'dashy'\n")),(0,o.yg)("p",null,"Note that if you are using Keycloak V 17 or older, you will also need to set ",(0,o.yg)("inlineCode",{parentName:"p"},"legacySupport: true")," (also under ",(0,o.yg)("inlineCode",{parentName:"p"},"appConfig.auth.keycloak"),"). This is because the API endpoint was updated in later versions."),(0,o.yg)("p",null,"If you use Keycloak with an external Identity Provier, you can set the ",(0,o.yg)("inlineCode",{parentName:"p"},"idpHint: 'alias-of-kc-idp'")," option to allow the IdP Hint to be passed to Keycloak. This will cause Keycloak to skip its login page and redirect the user directly to the specified IdP's login page. Set to the value of the 'Alias' field of the desired IdP as defined in Keycloak under 'Identity Providers'."),(0,o.yg)("h3",{id:"4-add-groups-and-roles-optional"},"4. Add groups and roles (Optional)"),(0,o.yg)("p",null,"Keycloak allows you to assign users roles and groups. You can use these values to configure who can access various sections or items in Dashy.\nKeycloak server administration and configuration is a deep topic; please refer to the ",(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/docs/latest/server_admin/index.html#assigning-permissions-and-access-using-roles-and-groups"},"server admin guide")," to see details about creating and assigning roles and groups.\nOnce you have groups or roles assigned to users you can configure access under each section or item ",(0,o.yg)("inlineCode",{parentName:"p"},"displayData.showForKeycloakUser")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"displayData.hideForKeycloakUser"),".\nBoth show and hide configurations accept a list of ",(0,o.yg)("inlineCode",{parentName:"p"},"groups")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"roles")," that limit access. If a users data matches one or more items in these lists they will be allowed or excluded as defined."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"sections:\n - name: DeveloperResources\n displayData:\n showForKeycloakUsers:\n roles: ['canViewDevResources']\n hideForKeycloakUsers:\n groups: ['ProductTeam']\n items:\n - title: Not Visible for developers\n displayData:\n hideForKeycloakUsers:\n groups: ['DevelopmentTeam']\n")),(0,o.yg)("p",null,"Depending on how you're hosting Dashy and Keycloak, you may also need to set some HTTP headers, to prevent a CORS error. This would typically be the ",(0,o.yg)("inlineCode",{parentName:"p"},"Access-Control-Allow-Origin [URL-of Dashy]")," on your Keycloak instance. See the ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/management.md#setting-headers"},"Setting Headers")," guide in the management docs for more info."),(0,o.yg)("p",null,"Your app is now secured :) When you load Dashy, it will redirect to your Keycloak login page, and any user without valid credentials will be prevented from accessing your dashboard."),(0,o.yg)("p",null,"From within the Keycloak console, you can then configure things like time-outs, password policies, etc. You can also backup your full Keycloak config, and it is recommended to do this, along with your Dashy config. You can spin up both Dashy and Keycloak simultaneously and restore both applications configs using a ",(0,o.yg)("inlineCode",{parentName:"p"},"docker-compose.yml")," file, and this is recommended."),(0,o.yg)("hr",null),(0,o.yg)("h2",{id:"alternative-authentication-methods"},"Alternative Authentication Methods"),(0,o.yg)("p",null,"If you are self-hosting Dashy, and require secure authentication to prevent unauthorized access, then you can either use Keycloak, or one of the following options:"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#authentication-server"},"Authentication Server")," - Put Dashy behind a self-hosted auth server"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#vpn"},"VPN")," - Use a VPN to tunnel into the network where Dashy is running"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#ip-based-access"},"IP-Based Access")," - Disallow access from all IP addresses, except your own"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#web-server-authentication"},"Web Server Authentication")," - Enable user control within your web server or proxy"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#oauth-services"},"OAuth Services")," - Implement a user management system using a cloud provider"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#static-site-hosting-providers"},"Password Protection (for cloud providers)")," - Enable password-protection on your site")),(0,o.yg)("h3",{id:"authentication-server"},"Authentication Server"),(0,o.yg)("h4",{id:"authelia"},"Authelia"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://www.authelia.com/"},"Authelia")," is an open-source full-featured authentication server, which can be self-hosted and either on bare metal, in a Docker container or in a Kubernetes cluster. It allows for fine-grained access control rules based on IP, path, users etc, and supports 2FA, simple password access or bypass policies for your domains."),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"git clone https://github.com/authelia/authelia.git")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"cd authelia/examples/compose/lite")),(0,o.yg)("li",{parentName:"ul"},"Modify the ",(0,o.yg)("inlineCode",{parentName:"li"},"users_database.yml")," the default username and password is authelia"),(0,o.yg)("li",{parentName:"ul"},"Modify the ",(0,o.yg)("inlineCode",{parentName:"li"},"configuration.yml")," and ",(0,o.yg)("inlineCode",{parentName:"li"},"docker-compose.yml")," with your respective domains and secrets"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"docker-compose up -d"))),(0,o.yg)("p",null,"For more information, see the ",(0,o.yg)("a",{parentName:"p",href:"https://www.authelia.com/docs/"},"Authelia docs")),(0,o.yg)("h3",{id:"vpn"},"VPN"),(0,o.yg)("p",null,"A catch-all solution to accessing services running from your home network remotely is to use a VPN. It means you do not need to worry about implementing complex authentication rules, or trusting the login implementation of individual applications. However it can be inconvenient to use on a day-to-day basis, and some public and corporate WiFi block VPN connections. Two popular VPN protocols are ",(0,o.yg)("a",{parentName:"p",href:"https://openvpn.net/"},"OpenVPN")," and ",(0,o.yg)("a",{parentName:"p",href:"https://www.wireguard.com/"},"WireGuard")),(0,o.yg)("h3",{id:"ip-based-access"},"IP-Based Access"),(0,o.yg)("p",null,"If you have a static IP or use a VPN to access your running services, then you can use conditional access to block access to Dashy from everyone except users of your pre-defined IP address. This feature is offered by most cloud providers, and supported by most web servers."),(0,o.yg)("h4",{id:"apache"},"Apache"),(0,o.yg)("p",null,"In Apache, this is configured in your ",(0,o.yg)("inlineCode",{parentName:"p"},".htaccess")," file in Dashy's root folder, and should look something like:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},"Order Deny,Allow\nDeny from all\nAllow from [your-ip]\n")),(0,o.yg)("h4",{id:"nginx"},"NGINX"),(0,o.yg)("p",null,"In NGINX you can specify ",(0,o.yg)("a",{parentName:"p",href:"https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http/"},"control access")," rules for a given site in your ",(0,o.yg)("inlineCode",{parentName:"p"},"nginx.conf")," or hosts file. For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},"server {\n listen 80;\n server_name www.dashy.example.com;\n location / {\n root /path/to/dashy/;\n passenger_enabled on;\n allow [your-ip];\n deny all;\n }\n }\n")),(0,o.yg)("h4",{id:"caddy"},"Caddy"),(0,o.yg)("p",null,"In Caddy, ",(0,o.yg)("a",{parentName:"p",href:"https://caddyserver.com/docs/caddyfile/matchers"},"Request Matchers")," can be used to filter requests"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},'dashy.site {\n @public_networks not remote_ip [your-ip]\n respond @public_networks "Access denied" 403\n}\n')),(0,o.yg)("h3",{id:"web-server-authentication"},"Web Server Authentication"),(0,o.yg)("p",null,"Most web servers make password protecting certain apps very easy. Note that you should also set up HTTPS and have a valid certificate in order for this to be secure."),(0,o.yg)("h4",{id:"apache-1"},"Apache"),(0,o.yg)("p",null,"First crate a ",(0,o.yg)("inlineCode",{parentName:"p"},".htaccess")," file in Dashy's route directory. Specify the auth type and path to where you want to store the password file (usually the same folder). For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},'AuthType Basic\nAuthName "Please Sign into Dashy"\nAuthUserFile /path/dashy/.htpasswd\nrequire valid-user\n')),(0,o.yg)("p",null,"Then create a ",(0,o.yg)("inlineCode",{parentName:"p"},".htpasswd")," file in the same directory. List users and their hashed passwords here, with one user on each line, and a colon between username and password (e.g. ",(0,o.yg)("inlineCode",{parentName:"p"},"[username]:[hashed-password]"),"). You will need to generate an MD5 hash of your desired password, this can be done with an ",(0,o.yg)("a",{parentName:"p",href:"https://www.web2generators.com/apache-tools/htpasswd-generator"},"online tool"),". Your file will look something like:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},"alicia:$apr1$jv0spemw$RzOX5/GgY69JMkgV6u16l0\n")),(0,o.yg)("h4",{id:"nginx-1"},"NGINX"),(0,o.yg)("p",null,"NGINX has an ",(0,o.yg)("a",{parentName:"p",href:"https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html"},"authentication module")," which can be used to add passwords to given sites, and is fairly simple to set up. Similar to above, you will need to create a ",(0,o.yg)("inlineCode",{parentName:"p"},".htpasswd")," file. Then just enable auth and specify the path to that file, for example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},'location / {\n auth_basic "closed site";\n auth_basic_user_file conf/htpasswd;\n}\n')),(0,o.yg)("h4",{id:"caddy-1"},"Caddy"),(0,o.yg)("p",null,"Caddy has a ",(0,o.yg)("a",{parentName:"p",href:"https://caddyserver.com/docs/caddyfile/directives/basicauth"},"basic-auth")," directive, where you specify a username and hash. The password hash needs to be base-64 encoded, the ",(0,o.yg)("a",{parentName:"p",href:"https://caddyserver.com/docs/command-line#caddy-hash-password"},(0,o.yg)("inlineCode",{parentName:"a"},"caddy hash-password"))," command can help with this. For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},"basicauth /secret/* {\n alicia JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX\n}\n")),(0,o.yg)("p",null,"For more info about implementing a single sign on for all your apps with Caddy, see ",(0,o.yg)("a",{parentName:"p",href:"https://joshstrange.com/securing-your-self-hosted-apps-with-single-signon/"},"this tutorial")),(0,o.yg)("h4",{id:"lighttpd"},"Lighttpd"),(0,o.yg)("p",null,"You can use the ",(0,o.yg)("a",{parentName:"p",href:"https://doc.lighttpd.net/lighttpd2/mod_auth.html"},"mod_auth")," module to secure your site with Lighttpd. Like with Apache, you need to first create a password file listing your usernames and hashed passwords, but in Lighttpd, it's usually called ",(0,o.yg)("inlineCode",{parentName:"p"},".lighttpdpassword"),"."),(0,o.yg)("p",null,"Then in your ",(0,o.yg)("inlineCode",{parentName:"p"},"lighttpd.conf")," file (usually in the ",(0,o.yg)("inlineCode",{parentName:"p"},"/etc/lighttpd/")," directory), load in the mod_auth module, and configure it's directives. For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},'server.modules += ( "mod_auth" )\nauth.debug = 2\nauth.backend = "plain"\nauth.backend.plain.userfile = "/home/lighttpd/.lighttpdpassword"\n\n$HTTP["host"] == "dashy.my-domain.net" {\n server.document-root = "/home/lighttpd/dashy.my-domain.net/http"\n server.errorlog = "/var/log/lighttpd/dashy.my-domain.net/error.log"\n accesslog.filename = "/var/log/lighttpd/dashy.my-domain.net/access.log"\n auth.require = (\n "/docs/" => (\n "method" => "basic",\n "realm" => "Password protected area",\n "require" => "user=alicia"\n )\n )\n}\n')),(0,o.yg)("p",null,"Restart your web server for changes to take effect."),(0,o.yg)("h3",{id:"oauth-services"},"OAuth Services"),(0,o.yg)("p",null,"There are also authentication services, such as ",(0,o.yg)("a",{parentName:"p",href:"https://www.ory.sh/"},"Ory.sh"),", ",(0,o.yg)("a",{parentName:"p",href:"https://developer.okta.com/"},"Okta"),", ",(0,o.yg)("a",{parentName:"p",href:"https://auth0.com/"},"Auth0"),", ",(0,o.yg)("a",{parentName:"p",href:"https://firebase.google.com/docs/auth/"},"Firebase"),". Implementing one of these solutions would involve some changes to the ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/src/utils/Auth.js"},(0,o.yg)("inlineCode",{parentName:"a"},"Auth.js"))," file, but should be fairly straightforward."),(0,o.yg)("h3",{id:"static-site-hosting-providers"},"Static Site Hosting Providers"),(0,o.yg)("p",null,"If you are hosting Dashy on a cloud platform, you will probably find that it has built-in support for password protected access to web apps. For more info, see the relevant docs for your provider, for example: ",(0,o.yg)("a",{parentName:"p",href:"https://docs.netlify.com/visitor-access/password-protection/"},"Netlify Password Protection"),", ",(0,o.yg)("a",{parentName:"p",href:"https://www.cloudflare.com/teams/access/"},"Cloudflare Access"),", ",(0,o.yg)("a",{parentName:"p",href:"https://aws.amazon.com/cognito/"},"AWS Cognito"),", ",(0,o.yg)("a",{parentName:"p",href:"https://docs.microsoft.com/en-us/azure/app-service/scenario-secure-app-authentication-app-service"},"Azure Authentication")," and ",(0,o.yg)("a",{parentName:"p",href:"https://vercel.com/docs/platform/projects#password-protection"},"Vercel Password Protection"),"."),(0,o.yg)("p",null,(0,o.yg)("strong",{parentName:"p"},(0,o.yg)("a",{parentName:"strong",href:"#authentication"},"\u2b06\ufe0f Back to Top"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/625b1ed7.af99ed07.js b/assets/js/625b1ed7.af99ed07.js new file mode 100644 index 00000000..ce578ad9 --- /dev/null +++ b/assets/js/625b1ed7.af99ed07.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[831],{5680:(e,a,t)=>{t.d(a,{xA:()=>p,yg:()=>y});var n=t(6540);function o(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function i(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function r(e){for(var a=1;a=0||(o[t]=e[t]);return o}(e,a);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=n.createContext({}),c=function(e){var a=n.useContext(l),t=a;return e&&(t="function"==typeof e?e(a):r(r({},a),e)),t},p=function(e){var a=c(e.components);return n.createElement(l.Provider,{value:a},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},d=n.forwardRef((function(e,a){var t=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(t),d=o,y=u["".concat(l,".").concat(d)]||u[d]||h[d]||i;return t?n.createElement(y,r(r({ref:a},p),{},{components:t})):n.createElement(y,r({ref:a},p))}));function y(e,a){var t=arguments,o=a&&a.mdxType;if("string"==typeof e||o){var i=t.length,r=new Array(i);r[0]=d;var s={};for(var l in a)hasOwnProperty.call(a,l)&&(s[l]=a[l]);s.originalType=e,s[u]="string"==typeof e?e:o,r[1]=s;for(var c=2;c{t.r(a),t.d(a,{contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var n=t(8168),o=(t(6540),t(5680));const i={},r="Authentication",s={unversionedId:"authentication",id:"authentication",isDocsHomePage:!1,title:"Authentication",description:"- Basic Auth",source:"@site/docs/authentication.md",sourceDirName:".",slug:"/authentication",permalink:"/docs/authentication",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/authentication.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Status Indicators",permalink:"/docs/status-indicators"},next:{title:"Keyboard Shortcuts",permalink:"/docs/searching"}},l=[{value:"Built-In Auth",id:"built-in-auth",children:[{value:"Setting Up Authentication",id:"setting-up-authentication",children:[]},{value:"Hash Password",id:"hash-password",children:[]},{value:"Logging In and Out",id:"logging-in-and-out",children:[]},{value:"Enabling Guest Access",id:"enabling-guest-access",children:[]},{value:"Granular Access",id:"granular-access",children:[]},{value:"Permissions",id:"permissions",children:[]},{value:"Security",id:"security",children:[]}]},{value:"Keycloak",id:"keycloak",children:[{value:"1. Deploy Keycloak",id:"1-deploy-keycloak",children:[]},{value:"2. Setup Keycloak Users",id:"2-setup-keycloak-users",children:[]},{value:"3. Enable Keycloak in Dashy Config File",id:"3-enable-keycloak-in-dashy-config-file",children:[]},{value:"4. Add groups and roles (Optional)",id:"4-add-groups-and-roles-optional",children:[]}]},{value:"Alternative Authentication Methods",id:"alternative-authentication-methods",children:[{value:"Authentication Server",id:"authentication-server",children:[]},{value:"VPN",id:"vpn",children:[]},{value:"IP-Based Access",id:"ip-based-access",children:[]},{value:"Web Server Authentication",id:"web-server-authentication",children:[]},{value:"OAuth Services",id:"oauth-services",children:[]},{value:"Static Site Hosting Providers",id:"static-site-hosting-providers",children:[]}]}],c={toc:l},p="wrapper";function u(e){let{components:a,...t}=e;return(0,o.yg)(p,(0,n.A)({},c,t,{components:a,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"authentication"},"Authentication"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#built-in-auth"},"Basic Auth"),(0,o.yg)("ul",{parentName:"li"},(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#setting-up-authentication"},"Setting Up Authentication")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#hash-password"},"Hash Password")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#logging-in-and-out"},"Logging In and Out")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#enabling-guest-access"},"Guest Access")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#granular-access"},"Per-User Access")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#security"},"Security Considerations")))),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#keycloak"},"Keycloak Auth"),(0,o.yg)("ul",{parentName:"li"},(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#1-deploy-keycloak"},"Deploying Keycloak")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#2-setup-keycloak-users"},"Setting up Keycloak")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#3-enable-keycloak-in-dashy-config-file"},"Configuring Dashy for Keycloak")))),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#alternative-authentication-methods"},"Alternative Authentication Methods"),(0,o.yg)("ul",{parentName:"li"},(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#vpn"},"VPN")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#ip-based-access"},"IP-Based Access")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#web-server-authentication"},"Web Server Authentication")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#oauth-services"},"OAuth Services")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#static-site-hosting-providers"},"Auth on Cloud Hosting Services"))))),(0,o.yg)("blockquote",null,(0,o.yg)("p",{parentName:"blockquote"},"[!IMPORTANT]","\nDashy's built-in auth is not indented to protect a publicly hosted instance against unauthorized access. Instead you should use an auth provider compatible with your reverse proxy, or access Dashy via your VPN. "),(0,o.yg)("p",{parentName:"blockquote"},"In cases where Dashy is only accessibly within your home network, and you just want to add a login page, then the built-in auth may be sufficient, but keep in mind that configuration can still be accessed.")),(0,o.yg)("h2",{id:"built-in-auth"},"Built-In Auth"),(0,o.yg)("p",null,"Dashy has a basic login page included, and frontend authentication. You can enable this by adding users to the ",(0,o.yg)("inlineCode",{parentName:"p"},"auth")," section under ",(0,o.yg)("inlineCode",{parentName:"p"},"appConfig")," in your ",(0,o.yg)("inlineCode",{parentName:"p"},"conf.yml"),". If this section is not specified, then no authentication will be required to access the app, and the homepage will resolve to your dashboard."),(0,o.yg)("h3",{id:"setting-up-authentication"},"Setting Up Authentication"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"auth")," property takes an array of users. Each user needs to include a username, hash and optional user type (",(0,o.yg)("inlineCode",{parentName:"p"},"admin")," or ",(0,o.yg)("inlineCode",{parentName:"p"},"normal"),"). The hash property is a ",(0,o.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/SHA-2"},"SHA-256 Hash")," of your desired password."),(0,o.yg)("p",null,"For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"appConfig:\n auth:\n users:\n - user: alicia\n hash: 4D1E58C90B3B94BCAD9848ECCACD6D2A8C9FBC5CA913304BBA5CDEAB36FEEFA3\n type: admin\n - user: bob\n hash: 5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8\n")),(0,o.yg)("h3",{id:"hash-password"},"Hash Password"),(0,o.yg)("p",null,"Dashy uses ",(0,o.yg)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Sha-256"},"SHA-256 Hash"),", a 64-character string, which you can generate using an online tool, such as ",(0,o.yg)("a",{parentName:"p",href:"https://passwordsgenerator.net/sha256-hash-generator/"},"this one")," or ",(0,o.yg)("a",{parentName:"p",href:"https://gchq.github.io/CyberChef/"},"CyberChef")," (which can be self-hosted/ ran locally)."),(0,o.yg)("p",null,"A hash is a one-way cryptographic function, meaning that it is easy to generate a hash for a given password, but very hard to determine the original password for a given hash. This means, that so long as your password is long, strong and unique, it is safe to store its hash in the clear. Having said that, you should never reuse passwords, hashes can be cracked by iterating over known password lists, generating a hash of each."),(0,o.yg)("h3",{id:"logging-in-and-out"},"Logging In and Out"),(0,o.yg)("p",null,"Once authentication is enabled, so long as there is no valid token in cookie storage, the application will redirect the user to the login page. When the user enters credentials in the login page, they will be checked, and if valid, then a token will be generated, and they can be redirected to the home page. If credentials are invalid, then an error message will be shown, and they will remain on the login page. Once in the application, to log out: the user can click the logout button (in the top-right), which will clear cookie storage, causing them to be redirected back to the login page."),(0,o.yg)("h3",{id:"enabling-guest-access"},"Enabling Guest Access"),(0,o.yg)("p",null,"With authentication set up, by default no access is allowed to your dashboard without first logging in with valid credentials. Guest mode can be enabled to allow for read-only access to a secured dashboard by any user, without the need to log in. A guest user cannot write any changes to the config file, but can apply modifications locally (stored in their browser). You can enable guest access, by setting ",(0,o.yg)("inlineCode",{parentName:"p"},"appConfig.auth.enableGuestAccess: true"),"."),(0,o.yg)("h3",{id:"granular-access"},"Granular Access"),(0,o.yg)("p",null,"You can use the following properties to make certain pages, sections or items only visible to some users, or hide pages, sections and items from guests."),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"hideForUsers")," - Page, Section or Item will be visible to all users, except for those specified in this list"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"showForUsers")," - Page, Section or Item will be hidden from all users, except for those specified in this list"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"hideForGuests")," - Page, Section or Item will be visible for logged in users, but not for guests")),(0,o.yg)("p",null,"For Example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"pages:\n - name: Home Lab\n path: home-lab.yml\n displayData:\n showForUsers: [admin]\n - name: Intranet\n path: intranet.yml\n displayData:\n hideForGuests: true\n hideForUsers: [alicia, bob]\n")),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"- name: Code Analysis & Monitoring\n icon: fas fa-code\n displayData:\n cols: 2\n hideForUsers: [alicia, bob]\n items:\n ...\n")),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"- name: Deployment Pipelines\n icon: fas fa-rocket\n displayData:\n hideForGuests: true\n items:\n - title: Hide Me\n displayData:\n hideForUsers: [alicia, bob]\n")),(0,o.yg)("h3",{id:"permissions"},"Permissions"),(0,o.yg)("p",null,"Any user who is not an admin (with ",(0,o.yg)("inlineCode",{parentName:"p"},"type: admin"),") will not be able to write changes to disk."),(0,o.yg)("p",null,"You can also prevent any user from writing changes to disk, using ",(0,o.yg)("inlineCode",{parentName:"p"},"preventWriteToDisk"),". Or prevent any changes from being saved locally in browser storage, using ",(0,o.yg)("inlineCode",{parentName:"p"},"preventLocalSave"),". Both properties can be found under ",(0,o.yg)("a",{parentName:"p",href:"/docs/configuring#appconfig-optional"},(0,o.yg)("inlineCode",{parentName:"a"},"appConfig")),"."),(0,o.yg)("p",null,"To disable all UI config features, including View Config, set ",(0,o.yg)("inlineCode",{parentName:"p"},"disableConfiguration"),". Alternatively you can disable UI config features for all non admin users by setting ",(0,o.yg)("inlineCode",{parentName:"p"},"disableConfigurationForNonAdmin")," to true."),(0,o.yg)("h3",{id:"security"},"Security"),(0,o.yg)("p",null,"With basic auth, all logic is happening on the client-side, which could mean a skilled user could manipulate the code to view parts of your configuration, including the hash. If the SHA-256 hash is of a common password, it may be possible to determine it, using a lookup table, in order to find the original password. Which can be used to manually generate the auth token, that can then be inserted into session storage, to become a valid logged in user. Therefore, you should always use a long, strong and unique password, and if you instance contains security-critical info and/ or is exposed directly to the internet, and alternative authentication method may be better. The purpose of the login page is merely to prevent immediate unauthorized access to your homepage."),(0,o.yg)("p",null,(0,o.yg)("strong",{parentName:"p"},(0,o.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))),(0,o.yg)("hr",null),(0,o.yg)("h2",{id:"keycloak"},"Keycloak"),(0,o.yg)("p",null,"Dashy also supports using a ",(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/"},"Keycloak")," authentication server. The setup for this is a bit more involved, but it gives you greater security overall, useful for if your instance is exposed to the internet."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/about.html"},"Keycloak")," is a Java-based ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/keycloak/keycloak"},"open source"),", high-performance, secure authentication system, supported by ",(0,o.yg)("a",{parentName:"p",href:"https://www.redhat.com/en"},"RedHat"),". It is easy to setup (",(0,o.yg)("a",{parentName:"p",href:"https://quay.io/repository/keycloak/keycloak"},"with Docker"),"), and enables you to secure multiple self-hosted applications with single-sign-on using standard protocols (OpenID Connect, OAuth 2.0, SAML 2.0 and social login). It's also very customizable, you can write or use custom ",(0,o.yg)("a",{parentName:"p",href:"https://wjw465150.gitbooks.io/keycloak-documentation/content/server_development/topics/themes.html"},"themes"),", ",(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/extensions.html"},"plugins"),", ",(0,o.yg)("a",{parentName:"p",href:"https://wjw465150.gitbooks.io/keycloak-documentation/content/server_admin/topics/authentication/password-policies.html"},"password policies")," and more.\nThe following guide will walk you through setting up Keycloak with Dashy. If you already have a Keycloak instance configured, then skip to Step 3."),(0,o.yg)("h3",{id:"1-deploy-keycloak"},"1. Deploy Keycloak"),(0,o.yg)("p",null,"First thing to do is to spin up a new instance of Keycloak. You will need ",(0,o.yg)("a",{parentName:"p",href:"https://docs.docker.com/engine/install/"},"Docker installed"),", and can then choose a tag, and pull the container from ",(0,o.yg)("a",{parentName:"p",href:"https://quay.io/repository/keycloak/keycloak"},"quay.io/keycloak/keycloak")),(0,o.yg)("p",null,"Use the following run command, replacing the attributes (default credentials, port and name), or incorporate this into your docker-compose file."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-bash"},"docker run -d \\\n -p 8081:8080 \\\n --name auth-server \\\n -e KEYCLOAK_USER=admin \\\n -e KEYCLOAK_PASSWORD=admin \\\n quay.io/keycloak/keycloak:15.0.2\n")),(0,o.yg)("p",null,"If you need to pull from DockerHub, a non-official image is available ",(0,o.yg)("a",{parentName:"p",href:"https://registry.hub.docker.com/r/jboss/keycloak"},"here"),". Or if you would prefer not to use Docker, you can also directly install Keycloak from source, following ",(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/docs/latest/getting_started/index.html"},"this guide"),"."),(0,o.yg)("p",null,"You should now be able to access the Keycloak web interface, using the port specified above (e.g. ",(0,o.yg)("inlineCode",{parentName:"p"},"http://127.0.0.1:8081"),"), login with the default credentials, and when prompted create a new password."),(0,o.yg)("h3",{id:"2-setup-keycloak-users"},"2. Setup Keycloak Users"),(0,o.yg)("p",null,"Before we can use Keycloak, we must first set it up with some users. Keycloak uses Realms (similar to tenants) to create isolated groups of users. You must create a Realm before you will be able to add your first user."),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"Head over to the admin console"),(0,o.yg)("li",{parentName:"ol"},"In the top-left corner there is a dropdown called 'Master', hover over it and then click 'Add Realm'"),(0,o.yg)("li",{parentName:"ol"},"Give your realm a name, and hit 'Create'")),(0,o.yg)("p",null,"You can now create your first user."),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"In the left-hand menu, click 'Users', then 'Add User'"),(0,o.yg)("li",{parentName:"ol"},"Fill in the form, including username and hit 'Save'"),(0,o.yg)("li",{parentName:"ol"},"Under the 'Credentials' tab, give the new user an initial password. They will be prompted to change this after first login")),(0,o.yg)("p",null,"The last thing we need to do in the Keycloak admin console is to create a new client"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"Within your new realm, navigate to 'Clients' on the left-hand side, then click 'Create' in the top-right"),(0,o.yg)("li",{parentName:"ol"},"Choose a 'Client ID', set 'Client Protocol' to 'openid-connect', and for 'Valid Redirect URIs' put a URL pattern to where you're hosting Dashy (if you're just testing locally, then * is fine), and do the same for the 'Web Origins' field"),(0,o.yg)("li",{parentName:"ol"},"Make note of your client-id, and click 'Save'")),(0,o.yg)("h3",{id:"3-enable-keycloak-in-dashy-config-file"},"3. Enable Keycloak in Dashy Config File"),(0,o.yg)("p",null,"Now that your Keycloak instance is up and running, all that's left to do is to configure Dashy to use it. Under ",(0,o.yg)("inlineCode",{parentName:"p"},"appConfig"),", set ",(0,o.yg)("inlineCode",{parentName:"p"},"auth.enableKeycloak: true"),", then fill in the details in ",(0,o.yg)("inlineCode",{parentName:"p"},"auth.keycloak"),", including: ",(0,o.yg)("inlineCode",{parentName:"p"},"serverUrl")," - the URL where your Keycloak instance is hosted, ",(0,o.yg)("inlineCode",{parentName:"p"},"realm")," - the name you gave your Realm, and ",(0,o.yg)("inlineCode",{parentName:"p"},"clientId")," - the Client ID you chose.\nFor example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"appConfig:\n ...\n auth:\n enableKeycloak: true\n keycloak:\n serverUrl: 'http://localhost:8081'\n realm: 'alicia-homelab'\n clientId: 'dashy'\n")),(0,o.yg)("p",null,"Note that if you are using Keycloak V 17 or older, you will also need to set ",(0,o.yg)("inlineCode",{parentName:"p"},"legacySupport: true")," (also under ",(0,o.yg)("inlineCode",{parentName:"p"},"appConfig.auth.keycloak"),"). This is because the API endpoint was updated in later versions."),(0,o.yg)("p",null,"If you use Keycloak with an external Identity Provier, you can set the ",(0,o.yg)("inlineCode",{parentName:"p"},"idpHint: 'alias-of-kc-idp'")," option to allow the IdP Hint to be passed to Keycloak. This will cause Keycloak to skip its login page and redirect the user directly to the specified IdP's login page. Set to the value of the 'Alias' field of the desired IdP as defined in Keycloak under 'Identity Providers'."),(0,o.yg)("h3",{id:"4-add-groups-and-roles-optional"},"4. Add groups and roles (Optional)"),(0,o.yg)("p",null,"Keycloak allows you to assign users roles and groups. You can use these values to configure who can access various sections or items in Dashy.\nKeycloak server administration and configuration is a deep topic; please refer to the ",(0,o.yg)("a",{parentName:"p",href:"https://www.keycloak.org/docs/latest/server_admin/index.html#assigning-permissions-and-access-using-roles-and-groups"},"server admin guide")," to see details about creating and assigning roles and groups.\nOnce you have groups or roles assigned to users you can configure access under each section or item ",(0,o.yg)("inlineCode",{parentName:"p"},"displayData.showForKeycloakUser")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"displayData.hideForKeycloakUser"),".\nBoth show and hide configurations accept a list of ",(0,o.yg)("inlineCode",{parentName:"p"},"groups")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"roles")," that limit access. If a users data matches one or more items in these lists they will be allowed or excluded as defined."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-yaml"},"sections:\n - name: DeveloperResources\n displayData:\n showForKeycloakUsers:\n roles: ['canViewDevResources']\n hideForKeycloakUsers:\n groups: ['ProductTeam']\n items:\n - title: Not Visible for developers\n displayData:\n hideForKeycloakUsers:\n groups: ['DevelopmentTeam']\n")),(0,o.yg)("p",null,"Depending on how you're hosting Dashy and Keycloak, you may also need to set some HTTP headers, to prevent a CORS error. This would typically be the ",(0,o.yg)("inlineCode",{parentName:"p"},"Access-Control-Allow-Origin [URL-of Dashy]")," on your Keycloak instance. See the ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/docs/management.md#setting-headers"},"Setting Headers")," guide in the management docs for more info."),(0,o.yg)("p",null,"Your app is now secured :) When you load Dashy, it will redirect to your Keycloak login page, and any user without valid credentials will be prevented from accessing your dashboard."),(0,o.yg)("p",null,"From within the Keycloak console, you can then configure things like time-outs, password policies, etc. You can also backup your full Keycloak config, and it is recommended to do this, along with your Dashy config. You can spin up both Dashy and Keycloak simultaneously and restore both applications configs using a ",(0,o.yg)("inlineCode",{parentName:"p"},"docker-compose.yml")," file, and this is recommended."),(0,o.yg)("hr",null),(0,o.yg)("h2",{id:"alternative-authentication-methods"},"Alternative Authentication Methods"),(0,o.yg)("p",null,"If you are self-hosting Dashy, and require secure authentication to prevent unauthorized access, then you can either use Keycloak, or one of the following options:"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#authentication-server"},"Authentication Server")," - Put Dashy behind a self-hosted auth server"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#vpn"},"VPN")," - Use a VPN to tunnel into the network where Dashy is running"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#ip-based-access"},"IP-Based Access")," - Disallow access from all IP addresses, except your own"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#web-server-authentication"},"Web Server Authentication")," - Enable user control within your web server or proxy"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#oauth-services"},"OAuth Services")," - Implement a user management system using a cloud provider"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"#static-site-hosting-providers"},"Password Protection (for cloud providers)")," - Enable password-protection on your site")),(0,o.yg)("h3",{id:"authentication-server"},"Authentication Server"),(0,o.yg)("h4",{id:"authelia"},"Authelia"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://www.authelia.com/"},"Authelia")," is an open-source full-featured authentication server, which can be self-hosted and either on bare metal, in a Docker container or in a Kubernetes cluster. It allows for fine-grained access control rules based on IP, path, users etc, and supports 2FA, simple password access or bypass policies for your domains."),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"git clone https://github.com/authelia/authelia.git")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"cd authelia/examples/compose/lite")),(0,o.yg)("li",{parentName:"ul"},"Modify the ",(0,o.yg)("inlineCode",{parentName:"li"},"users_database.yml")," the default username and password is authelia"),(0,o.yg)("li",{parentName:"ul"},"Modify the ",(0,o.yg)("inlineCode",{parentName:"li"},"configuration.yml")," and ",(0,o.yg)("inlineCode",{parentName:"li"},"docker-compose.yml")," with your respective domains and secrets"),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"docker-compose up -d"))),(0,o.yg)("p",null,"For more information, see the ",(0,o.yg)("a",{parentName:"p",href:"https://www.authelia.com/docs/"},"Authelia docs")),(0,o.yg)("h3",{id:"vpn"},"VPN"),(0,o.yg)("p",null,"A catch-all solution to accessing services running from your home network remotely is to use a VPN. It means you do not need to worry about implementing complex authentication rules, or trusting the login implementation of individual applications. However it can be inconvenient to use on a day-to-day basis, and some public and corporate WiFi block VPN connections. Two popular VPN protocols are ",(0,o.yg)("a",{parentName:"p",href:"https://openvpn.net/"},"OpenVPN")," and ",(0,o.yg)("a",{parentName:"p",href:"https://www.wireguard.com/"},"WireGuard")),(0,o.yg)("h3",{id:"ip-based-access"},"IP-Based Access"),(0,o.yg)("p",null,"If you have a static IP or use a VPN to access your running services, then you can use conditional access to block access to Dashy from everyone except users of your pre-defined IP address. This feature is offered by most cloud providers, and supported by most web servers."),(0,o.yg)("h4",{id:"apache"},"Apache"),(0,o.yg)("p",null,"In Apache, this is configured in your ",(0,o.yg)("inlineCode",{parentName:"p"},".htaccess")," file in Dashy's root folder, and should look something like:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},"Order Deny,Allow\nDeny from all\nAllow from [your-ip]\n")),(0,o.yg)("h4",{id:"nginx"},"NGINX"),(0,o.yg)("p",null,"In NGINX you can specify ",(0,o.yg)("a",{parentName:"p",href:"https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http/"},"control access")," rules for a given site in your ",(0,o.yg)("inlineCode",{parentName:"p"},"nginx.conf")," or hosts file. For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},"server {\n listen 80;\n server_name www.dashy.example.com;\n location / {\n root /path/to/dashy/;\n passenger_enabled on;\n allow [your-ip];\n deny all;\n }\n }\n")),(0,o.yg)("h4",{id:"caddy"},"Caddy"),(0,o.yg)("p",null,"In Caddy, ",(0,o.yg)("a",{parentName:"p",href:"https://caddyserver.com/docs/caddyfile/matchers"},"Request Matchers")," can be used to filter requests"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},'dashy.site {\n @public_networks not remote_ip [your-ip]\n respond @public_networks "Access denied" 403\n}\n')),(0,o.yg)("h3",{id:"web-server-authentication"},"Web Server Authentication"),(0,o.yg)("p",null,"Most web servers make password protecting certain apps very easy. Note that you should also set up HTTPS and have a valid certificate in order for this to be secure."),(0,o.yg)("h4",{id:"apache-1"},"Apache"),(0,o.yg)("p",null,"First crate a ",(0,o.yg)("inlineCode",{parentName:"p"},".htaccess")," file in Dashy's route directory. Specify the auth type and path to where you want to store the password file (usually the same folder). For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},'AuthType Basic\nAuthName "Please Sign into Dashy"\nAuthUserFile /path/dashy/.htpasswd\nrequire valid-user\n')),(0,o.yg)("p",null,"Then create a ",(0,o.yg)("inlineCode",{parentName:"p"},".htpasswd")," file in the same directory. List users and their hashed passwords here, with one user on each line, and a colon between username and password (e.g. ",(0,o.yg)("inlineCode",{parentName:"p"},"[username]:[hashed-password]"),"). You will need to generate an MD5 hash of your desired password, this can be done with an ",(0,o.yg)("a",{parentName:"p",href:"https://www.web2generators.com/apache-tools/htpasswd-generator"},"online tool"),". Your file will look something like:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},"alicia:$apr1$jv0spemw$RzOX5/GgY69JMkgV6u16l0\n")),(0,o.yg)("h4",{id:"nginx-1"},"NGINX"),(0,o.yg)("p",null,"NGINX has an ",(0,o.yg)("a",{parentName:"p",href:"https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html"},"authentication module")," which can be used to add passwords to given sites, and is fairly simple to set up. Similar to above, you will need to create a ",(0,o.yg)("inlineCode",{parentName:"p"},".htpasswd")," file. Then just enable auth and specify the path to that file, for example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},'location / {\n auth_basic "closed site";\n auth_basic_user_file conf/htpasswd;\n}\n')),(0,o.yg)("h4",{id:"caddy-1"},"Caddy"),(0,o.yg)("p",null,"Caddy has a ",(0,o.yg)("a",{parentName:"p",href:"https://caddyserver.com/docs/caddyfile/directives/basicauth"},"basic-auth")," directive, where you specify a username and hash. The password hash needs to be base-64 encoded, the ",(0,o.yg)("a",{parentName:"p",href:"https://caddyserver.com/docs/command-line#caddy-hash-password"},(0,o.yg)("inlineCode",{parentName:"a"},"caddy hash-password"))," command can help with this. For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},"basicauth /secret/* {\n alicia JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX\n}\n")),(0,o.yg)("p",null,"For more info about implementing a single sign on for all your apps with Caddy, see ",(0,o.yg)("a",{parentName:"p",href:"https://joshstrange.com/securing-your-self-hosted-apps-with-single-signon/"},"this tutorial")),(0,o.yg)("h4",{id:"lighttpd"},"Lighttpd"),(0,o.yg)("p",null,"You can use the ",(0,o.yg)("a",{parentName:"p",href:"https://doc.lighttpd.net/lighttpd2/mod_auth.html"},"mod_auth")," module to secure your site with Lighttpd. Like with Apache, you need to first create a password file listing your usernames and hashed passwords, but in Lighttpd, it's usually called ",(0,o.yg)("inlineCode",{parentName:"p"},".lighttpdpassword"),"."),(0,o.yg)("p",null,"Then in your ",(0,o.yg)("inlineCode",{parentName:"p"},"lighttpd.conf")," file (usually in the ",(0,o.yg)("inlineCode",{parentName:"p"},"/etc/lighttpd/")," directory), load in the mod_auth module, and configure it's directives. For example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-text"},'server.modules += ( "mod_auth" )\nauth.debug = 2\nauth.backend = "plain"\nauth.backend.plain.userfile = "/home/lighttpd/.lighttpdpassword"\n\n$HTTP["host"] == "dashy.my-domain.net" {\n server.document-root = "/home/lighttpd/dashy.my-domain.net/http"\n server.errorlog = "/var/log/lighttpd/dashy.my-domain.net/error.log"\n accesslog.filename = "/var/log/lighttpd/dashy.my-domain.net/access.log"\n auth.require = (\n "/docs/" => (\n "method" => "basic",\n "realm" => "Password protected area",\n "require" => "user=alicia"\n )\n )\n}\n')),(0,o.yg)("p",null,"Restart your web server for changes to take effect."),(0,o.yg)("h3",{id:"oauth-services"},"OAuth Services"),(0,o.yg)("p",null,"There are also authentication services, such as ",(0,o.yg)("a",{parentName:"p",href:"https://www.ory.sh/"},"Ory.sh"),", ",(0,o.yg)("a",{parentName:"p",href:"https://developer.okta.com/"},"Okta"),", ",(0,o.yg)("a",{parentName:"p",href:"https://auth0.com/"},"Auth0"),", ",(0,o.yg)("a",{parentName:"p",href:"https://firebase.google.com/docs/auth/"},"Firebase"),". Implementing one of these solutions would involve some changes to the ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/src/utils/Auth.js"},(0,o.yg)("inlineCode",{parentName:"a"},"Auth.js"))," file, but should be fairly straightforward."),(0,o.yg)("h3",{id:"static-site-hosting-providers"},"Static Site Hosting Providers"),(0,o.yg)("p",null,"If you are hosting Dashy on a cloud platform, you will probably find that it has built-in support for password protected access to web apps. For more info, see the relevant docs for your provider, for example: ",(0,o.yg)("a",{parentName:"p",href:"https://docs.netlify.com/visitor-access/password-protection/"},"Netlify Password Protection"),", ",(0,o.yg)("a",{parentName:"p",href:"https://www.cloudflare.com/teams/access/"},"Cloudflare Access"),", ",(0,o.yg)("a",{parentName:"p",href:"https://aws.amazon.com/cognito/"},"AWS Cognito"),", ",(0,o.yg)("a",{parentName:"p",href:"https://docs.microsoft.com/en-us/azure/app-service/scenario-secure-app-authentication-app-service"},"Azure Authentication")," and ",(0,o.yg)("a",{parentName:"p",href:"https://vercel.com/docs/platform/projects#password-protection"},"Vercel Password Protection"),"."),(0,o.yg)("p",null,(0,o.yg)("strong",{parentName:"p"},(0,o.yg)("a",{parentName:"strong",href:"#top"},"\u2b06\ufe0f Back to Top"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9be9f402.10e8571e.js b/assets/js/9be9f402.10e8571e.js deleted file mode 100644 index 4c9bd3b2..00000000 --- a/assets/js/9be9f402.10e8571e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[552],{5680:(e,t,a)=>{a.d(t,{xA:()=>y,yg:()=>u});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=n.createContext({}),p=function(e){var t=n.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},y=function(e){var t=p(e.components);return n.createElement(o.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},s=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,y=g(e,["components","mdxType","originalType","parentName"]),d=p(a),s=r,u=d["".concat(o,".").concat(s)]||d[s]||m[s]||l;return a?n.createElement(u,i(i({ref:t},y),{},{components:a})):n.createElement(u,i({ref:t},y))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,i=new Array(l);i[0]=s;var g={};for(var o in t)hasOwnProperty.call(t,o)&&(g[o]=t[o]);g.originalType=e,g[d]="string"==typeof e?e:r,i[1]=g;for(var p=2;p{a.r(t),a.d(t,{contentTitle:()=>i,default:()=>d,frontMatter:()=>l,metadata:()=>g,toc:()=>o});var n=a(8168),r=(a(6540),a(5680));const l={},i="Widgets",g={unversionedId:"widgets",id:"widgets",isDocsHomePage:!1,title:"Widgets",description:"Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API.",source:"@site/docs/widgets.md",sourceDirName:".",slug:"/widgets",permalink:"/docs/widgets",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/widgets.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Icons",permalink:"/docs/icons"},next:{title:"Theming",permalink:"/docs/theming"}},o=[{value:"Contents",id:"contents",children:[]},{value:"General Widgets",id:"general-widgets",children:[{value:"Clock",id:"clock",children:[]},{value:"Weather",id:"weather",children:[]},{value:"Weather Forecast",id:"weather-forecast",children:[]},{value:"RSS Feed",id:"rss-feed",children:[]},{value:"Image",id:"image",children:[]},{value:"Public IP",id:"public-ip",children:[]},{value:"IP Blacklist",id:"ip-blacklist",children:[]},{value:"Domain Monitor",id:"domain-monitor",children:[]},{value:"Crypto Watch List",id:"crypto-watch-list",children:[]},{value:"Crypto Token Price History",id:"crypto-token-price-history",children:[]},{value:"Wallet Balance",id:"wallet-balance",children:[]},{value:"Code Stats",id:"code-stats",children:[]},{value:"Mullvad Status",id:"mullvad-status",children:[]},{value:"AnonAddy",id:"anonaddy",children:[]},{value:"Vulnerability Feed",id:"vulnerability-feed",children:[]},{value:"Exchange Rates",id:"exchange-rates",children:[]},{value:"Public Holidays",id:"public-holidays",children:[]},{value:"Covid-19 Status",id:"covid-19-status",children:[]},{value:"Sports Scores",id:"sports-scores",children:[]},{value:"News Headlines",id:"news-headlines",children:[]},{value:"TFL Status",id:"tfl-status",children:[]},{value:"Stock Price History",id:"stock-price-history",children:[]},{value:"ETH Gas Prices",id:"eth-gas-prices",children:[]},{value:"Joke",id:"joke",children:[]},{value:"XKCD Comics",id:"xkcd-comics",children:[]},{value:"Flight Data",id:"flight-data",children:[]},{value:"Astronomy Picture of the Day",id:"astronomy-picture-of-the-day",children:[]},{value:"GitHub Trending",id:"github-trending",children:[]},{value:"GitHub Profile Stats",id:"github-profile-stats",children:[]},{value:"HealthChecks Status",id:"healthchecks-status",children:[]},{value:"Hackernews Trending",id:"hackernews-trending",children:[]},{value:"MVG Departure",id:"mvg-departure",children:[]},{value:"MVG Connection",id:"mvg-connection",children:[]},{value:"Custom search",id:"custom-search",children:[]},{value:"RescueTime Overview",id:"rescuetime-overview",children:[]}]},{value:"Self-Hosted Services Widgets",id:"self-hosted-services-widgets",children:[{value:"System Info",id:"system-info",children:[]},{value:"Cron Monitoring (Health Checks)",id:"cron-monitoring-health-checks",children:[]},{value:"CPU History (NetData)",id:"cpu-history-netdata",children:[]},{value:"Memory History (NetData)",id:"memory-history-netdata",children:[]},{value:"Load History (NetData)",id:"load-history-netdata",children:[]},{value:"Pi Hole Stats",id:"pi-hole-stats",children:[]},{value:"Pi Hole Queries",id:"pi-hole-queries",children:[]},{value:"Pi Hole Recent Traffic",id:"pi-hole-recent-traffic",children:[]},{value:"Stat Ping Statuses",id:"stat-ping-statuses",children:[]},{value:"Synology Download Station",id:"synology-download-station",children:[]},{value:"AdGuard Home Block Stats",id:"adguard-home-block-stats",children:[]},{value:"AdGuard Home Filters",id:"adguard-home-filters",children:[]},{value:"AdGuard Home DNS Info",id:"adguard-home-dns-info",children:[]},{value:"AdGuard Home Top Domains",id:"adguard-home-top-domains",children:[]},{value:"Nextcloud User",id:"nextcloud-user",children:[]},{value:"Nextcloud User Statuses",id:"nextcloud-user-statuses",children:[]},{value:"Nextcloud Notifications",id:"nextcloud-notifications",children:[]},{value:"Nextcloud System",id:"nextcloud-system",children:[]},{value:"Nextcloud Stats",id:"nextcloud-stats",children:[]},{value:"Nextcloud PHP OPcache Stats",id:"nextcloud-php-opcache-stats",children:[]},{value:"Proxmox lists",id:"proxmox-lists",children:[]},{value:"Sabnzbd",id:"sabnzbd",children:[]},{value:"Gluetun VPN Info",id:"gluetun-vpn-info",children:[]},{value:"Drone CI Builds",id:"drone-ci-builds",children:[]},{value:"Linkding",id:"linkding",children:[]}]},{value:"System Resource Monitoring",id:"system-resource-monitoring",children:[{value:"Glances",id:"glances",children:[]},{value:"Current CPU Usage",id:"current-cpu-usage",children:[]},{value:"Current CPU Usage Speedometer",id:"current-cpu-usage-speedometer",children:[]},{value:"CPU Usage Per Core",id:"cpu-usage-per-core",children:[]},{value:"CPU Usage History",id:"cpu-usage-history",children:[]},{value:"Current Memory Usage",id:"current-memory-usage",children:[]},{value:"Current Memory Usage Speedometer",id:"current-memory-usage-speedometer",children:[]},{value:"Memory Usage History",id:"memory-usage-history",children:[]},{value:"Disk Space",id:"disk-space",children:[]},{value:"Disk IO",id:"disk-io",children:[]},{value:"System Load",id:"system-load",children:[]},{value:"System Load History",id:"system-load-history",children:[]},{value:"Network Interfaces",id:"network-interfaces",children:[]},{value:"Network Traffic",id:"network-traffic",children:[]},{value:"Resource Usage Alerts",id:"resource-usage-alerts",children:[]},{value:"IP Address",id:"ip-address",children:[]},{value:"CPU Temp",id:"cpu-temp",children:[]}]},{value:"Dynamic Widgets",id:"dynamic-widgets",children:[{value:"Iframe Widget",id:"iframe-widget",children:[]},{value:"HTML Embedded Widget",id:"html-embedded-widget",children:[]},{value:"API Response",id:"api-response",children:[]},{value:"Prometheus Data",id:"prometheus-data",children:[]},{value:"Data Feed",id:"data-feed",children:[]}]},{value:"Usage & Customizations",id:"usage--customizations",children:[{value:"Widget Usage Guide",id:"widget-usage-guide",children:[]},{value:"Continuous Updates",id:"continuous-updates",children:[]},{value:"Proxying Requests",id:"proxying-requests",children:[]},{value:"Setting Timeout",id:"setting-timeout",children:[]},{value:"Adding Labels",id:"adding-labels",children:[]},{value:"Ignoring Errors",id:"ignoring-errors",children:[]},{value:"Widget Styling",id:"widget-styling",children:[]},{value:"Customizing Charts",id:"customizing-charts",children:[]},{value:"Language Translations",id:"language-translations",children:[]},{value:"Widget UI Options",id:"widget-ui-options",children:[]},{value:"Build your own Widget",id:"build-your-own-widget",children:[]},{value:"Requesting a Widget",id:"requesting-a-widget",children:[]},{value:"Troubleshooting Widget Errors",id:"troubleshooting-widget-errors",children:[]},{value:"Raising an Issue",id:"raising-an-issue",children:[]}]}],p={toc:o},y="wrapper";function d(e){let{components:t,...a}=e;return(0,r.yg)(y,(0,n.A)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"widgets"},"Widgets"),(0,r.yg)("p",null,"Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API."),(0,r.yg)("h2",{id:"contents"},"Contents"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#general-widgets"},"General Widgets")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#clock"},"Clock")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#weather"},"Weather")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#weather-forecast"},"Weather Forecast")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#rss-feed"},"RSS Feed")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#image"},"Image")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#public-ip"},"Public IP Address")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#ip-blacklist"},"IP Blacklist Checker")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#domain-monitor"},"Domain Monitor")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#crypto-watch-list"},"Crypto Watch List")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#crypto-token-price-history"},"Crypto Price History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#wallet-balance"},"Crypto Wallet Balance")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#code-stats"},"Code Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#mullvad-status"},"Mullvad Status")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#anonaddy"},"Email Aliases (AnonAddy)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#vulnerability-feed"},"Vulnerability Feed")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#exchange-rates"},"Exchange Rates")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#public-holidays"},"Public Holidays")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#covid-19-status"},"Covid-19 Status")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sports-scores"},"Sports Scores")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#news-headlines"},"News Headlines")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#tfl-status"},"TFL Status")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#stock-price-history"},"Stock Price History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#eth-gas-prices"},"ETH Gas Prices")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#joke"},"Joke of the Day")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#xkcd-comics"},"XKCD Comics")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#flight-data"},"Flight Data")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#astronomy-picture-of-the-day"},"NASA APOD")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#github-trending"},"GitHub Trending")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#github-profile-stats"},"GitHub Profile Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#healthchecks-status"},"Healthchecks Status")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#hackernews-trending"},"Hackernews Trending")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#mvg-departure"},"Mvg Departure")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#mvg-connection"},"Mvg Connection")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#custom-search"},"Custom search")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#rescuetime-overview"},"Rescuetime overview")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#self-hosted-services-widgets"},"Self-Hosted Services Widgets")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#system-info"},"System Info")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cron-monitoring-health-checks"},"Cron Monitoring")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpu-history-netdata"},"CPU History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#memory-history-netdata"},"Memory History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#load-history-netdata"},"System Load History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pi-hole-stats"},"Pi Hole Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pi-hole-queries"},"Pi Hole Queries")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pi-hole-recent-traffic"},"Pi Hole Recent Traffic")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#stat-ping-statuses"},"Stat Ping Statuses")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#synology-download-station"},"Synology Download Station")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adguard-home-block-stats"},"AdGuard Home Block Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adguard-home-filters"},"AdGuard Home Filters")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adguard-home-dns-info"},"AdGuard Home DNS Info")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adguard-home-top-domains"},"AdGuard Home Top Domains")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-user"},"Nextcloud User")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-user-statuses"},"Nextcloud User Statuses")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-notifications"},"Nextcloud Notifications")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-system"},"Nextcloud System")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-stats"},"Nextcloud Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-php-opcache-stats"},"Nextcloud PHP OPcache")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#proxmox-lists"},"Proxmox lists")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sabnzbd"},"Sabnzbd")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#gluetun-vpn-info"},"Gluetun VPN Info")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#drone-ci-builds"},"Drone CI Build")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#linkding"},"Linkding")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#system-resource-monitoring"},"System Resource Monitoring")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#current-cpu-usage"},"CPU Usage Current")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpu-usage-per-core"},"CPU Usage Per Core")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpu-usage-history"},"CPU Usage History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#current-memory-usage"},"Memory Usage Current")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#memory-usage-history"},"Memory Usage History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#disk-space"},"Disk Space")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#disk-io"},"Disk IO")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#system-load"},"System Load")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#system-load-history"},"System Load History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#network-interfaces"},"Network Interfaces")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#network-traffic"},"Network Traffic")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#resource-usage-alerts"},"Resource Usage Alerts")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#ip-address"},"Public & Private IP")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpu-temp"},"CPU Temperature")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#dynamic-widgets"},"Dynamic Widgets")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#iframe-widget"},"Iframe Widget")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#html-embedded-widget"},"HTML Embed Widget")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#api-response"},"API Response")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#prometheus-data"},"Prometheus Data")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#data-feed"},"Data Feed")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#usage--customizations"},"Usage & Customizations")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#widget-usage-guide"},"Widget Usage Guide")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#continuous-updates"},"Continuous Updates")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#proxying-requests"},"Proxying Requests")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#setting-timeout"},"Setting Timeout")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adding-labels"},"Adding Labels")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#ignoring-errors"},"Ignoring Errors")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#widget-styling"},"Custom CSS Styling")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#customizing-charts"},"Customizing Charts")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#language-translations"},"Language Translations")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#widget-ui-options"},"Widget UI Options")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#build-your-own-widget"},"Building a Widget")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#requesting-a-widget"},"Requesting a Widget")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#troubleshooting-widget-errors"},"Troubleshooting"))))),(0,r.yg)("h2",{id:"general-widgets"},"General Widgets"),(0,r.yg)("h3",{id:"clock"},"Clock"),(0,r.yg)("p",null,"A simple, live-updating time and date widget with time-zone support. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/vjb4RTv/clock.png"})),(0,r.yg)("h4",{id:"options"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"timeZone"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The time zone to display date and time in.",(0,r.yg)("br",null)," Specified as Region/City, for example: ",(0,r.yg)("inlineCode",{parentName:"td"},"Australia/Melbourne"),". See the ",(0,r.yg)("a",{parentName:"td",href:"https://timezonedb.com/time-zones"},"Time Zone DB")," for a full list of supported TZs. Defaults to the browser / device's local time")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"format"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A country code for displaying the date and time in local format.",(0,r.yg)("br",null),"Specified as ",(0,r.yg)("inlineCode",{parentName:"td"},"[ISO-3166]-[ISO-639]"),", for example: ",(0,r.yg)("inlineCode",{parentName:"td"},"en-AU"),". See ",(0,r.yg)("a",{parentName:"td",href:"https://www.fincher.org/Utilities/CountryLanguageList.shtml"},"here")," for a full list of locales. Defaults to the browser / device's region")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customCityName"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default the city from the time-zone is shown, but setting this value will override that text")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideDate"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the date and city will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideSeconds"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", seconds will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"use12Hour"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", 12 hour time will be displayed. Defaults to the settings suggested by the current ",(0,r.yg)("inlineCode",{parentName:"td"},"format")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"timeZone"))))),(0,r.yg)("h4",{id:"example"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: clock\n options:\n timeZone: Europe/London\n format: en-GB\n hideDate: false\n")),(0,r.yg)("h4",{id:"info"},"Info"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No external data requests.")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"weather"},"Weather"),(0,r.yg)("p",null,"A simple, live-updating local weather component, showing temperature, conditions and more info."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/r6MCfsL/weather.png"})),(0,r.yg)("h4",{id:"options-1"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your OpenWeatherMap API key. You can get one for free at ",(0,r.yg)("a",{parentName:"td",href:"https://openweathermap.org/"},"openweathermap.org"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"city"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"units"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The units to use for displaying data, can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"metric")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"imperial"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"metric"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideDetails"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lat"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"To show weather for a specific location, you can provide the latitude and longitude coordinates. If provided, this will override the ",(0,r.yg)("inlineCode",{parentName:"td"},"city")," option")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"To show weather for a specific location, you can provide the latitude and longitude coordinates. If provided, this will override the ",(0,r.yg)("inlineCode",{parentName:"td"},"city")," option")))),(0,r.yg)("h4",{id:"example-1"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: weather\n options:\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n city: London\n units: metric\n hideDetails: true\n")),(0,r.yg)("h4",{id:"info-1"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://openweather.co.uk/privacy-policy"},"OWM Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"weather-forecast"},"Weather Forecast"),(0,r.yg)("p",null,"Displays the weather (temperature and conditions) for the next few days for a given location. Note that this requires either the free ",(0,r.yg)("a",{parentName:"p",href:"https://home.openweathermap.org/students"},"OpenWeatherMap Student Plan"),", or the Premium Plan."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/vshwgZB/weather-forecast.png"})),(0,r.yg)("h4",{id:"options-2"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your OpenWeatherMap API key. You can get one at ",(0,r.yg)("a",{parentName:"td",href:"https://openweathermap.org/"},"openweathermap.org")," or for free via the ",(0,r.yg)("a",{parentName:"td",href:"https://home.openweathermap.org/students"},"OWM Student Plan"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"city"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"numDays"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of days to display of forecast info to display. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"4"),", max ",(0,r.yg)("inlineCode",{parentName:"td"},"16")," days")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"units"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The units to use for displaying data, can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"metric")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"imperial"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"metric"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideDetails"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))))),(0,r.yg)("h4",{id:"example-2"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: weather-forecast\n options:\n city: California\n numDays: 6\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n units: imperial\n")),(0,r.yg)("h4",{id:"info-2"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udd34 Premium (free for personal use only)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://openweather.co.uk/privacy-policy"},"OWM Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"rss-feed"},"RSS Feed"),(0,r.yg)("p",null,"Display news and updates from any RSS-enabled service."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/N9mvLh4/rss-feed.png"})),(0,r.yg)("h4",{id:"options-3"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"rssUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL location of your RSS feed")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An API key for ",(0,r.yg)("a",{parentName:"td",href:"https://rss2json.com/"},"rss2json"),". It's free, and will allow you to make 10,000 requests per day, you can sign up ",(0,r.yg)("a",{parentName:"td",href:"https://rss2json.com/sign-up"},"here"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of posts to return. If you haven't specified an API key, this will be limited to 10")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"orderBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"How results should be sorted. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"pubDate"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"author")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"title"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"pubDate"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"orderDirection"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Order direction of feed items to return. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"asc")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"desc"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"desc"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"parseLocally"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If true parse the rss feed locally instead of using the rss2json API.")))),(0,r.yg)("h4",{id:"example-3"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: rss-feed\n options:\n rssUrl: https://www.schneier.com/blog/atom.xml\n apiKey: xxxx\n")),(0,r.yg)("h4",{id:"info-3"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free Plan (up to 10,000 requests / day)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://rss2json.com/privacy-policy"},"Rss2Json Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"image"},"Image"),(0,r.yg)("p",null,"Displays an image."),(0,r.yg)("p",null,"This may be useful if you have a service (such as Grafana - ",(0,r.yg)("a",{parentName:"p",href:"https://mattionline.de/grafana-api-export-graph-as-png/"},"see example"),"), which periodically exports charts or other data as an image."),(0,r.yg)("p",null,"You can also store images within Dashy's public directory (using a Docker volume), and reference them directly. E.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"-v ./path/to/my-homelab-logo.png:/app/public/logo.png"),", then in the widget ",(0,r.yg)("inlineCode",{parentName:"p"},"imagePath: /logo.png"),"."),(0,r.yg)("p",null,"Similarly, any web service that serves up widgets as image can be used. E.g. you could show current star chart for a GitHub repo, with: ",(0,r.yg)("inlineCode",{parentName:"p"},"imagePath: https://starchart.cc/Lissy93/dashy.svg"),"."),(0,r.yg)("p",null,"If you'd like to embed a live screenshot, of all or just part of a website, then this can be done using ",(0,r.yg)("a",{parentName:"p",href:"https://apiflash.com/"},"API Flash"),"."),(0,r.yg)("p",null,"Or what about showing a photo of the day? Try ",(0,r.yg)("inlineCode",{parentName:"p"},"https://source.unsplash.com/random/400x300")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"https://picsum.photos/400/300")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"300",src:"https://i.ibb.co/P48Y443/image-widget.png"})),(0,r.yg)("h4",{id:"options-4"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"imagePath"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The path (local or remote) of the image to display")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"imageWidth"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify a fixed width for rendered image. Accepts either integer value in ",(0,r.yg)("inlineCode",{parentName:"td"},"px"),", or any string value with units (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"420"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"100px"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"6.9rem"),") (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"imageHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify a fixed height for rendered image. Accepts either integer value in ",(0,r.yg)("inlineCode",{parentName:"td"},"px"),", or any string value with units (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"420"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"100px"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"6.9rem"),") (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"),")")))),(0,r.yg)("h4",{id:"example-4"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: image\n options:\n imagePath: https://i.ibb.co/yhbt6CY/dashy.png\n")),(0,r.yg)("h4",{id:"info-4"},"Info"),(0,r.yg)("p",null,"Unless image fetched from remote source, no external data request is made."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"public-ip"},"Public IP"),(0,r.yg)("p",null,'Often find yourself searching "What\'s my IP", just so you can check your VPN is still connected? This widget displays your public IP address, along with ISP name and approx location. Data can be fetched from either ',(0,r.yg)("a",{parentName:"p",href:"https://ipapi.co/"},"IpApi.co"),", ",(0,r.yg)("a",{parentName:"p",href:"https://ip-api.com/"},"IP-API.com")," or ",(0,r.yg)("a",{parentName:"p",href:"https://ipgeolocation.io/"},"IpGeolocation.io"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/vc3c8zN/public-ip.png"})),(0,r.yg)("h4",{id:"options-5"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"All fields are optional.")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"provider"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The name of the service to fetch IP address from. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"ipapi.co"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"ip-api")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"ipgeolocation"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"ipapi.co"),". Note, ",(0,r.yg)("inlineCode",{parentName:"td"},"ip-api")," doesn't work on HTTPS, and if you set to ",(0,r.yg)("inlineCode",{parentName:"td"},"ipgeolocation")," then you must also provide an API key")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only required if provider is set to ",(0,r.yg)("inlineCode",{parentName:"td"},"ipgeolocation"),". You can get a free API key ",(0,r.yg)("a",{parentName:"td",href:"https://ipgeolocation.io/signup.html"},"here"))))),(0,r.yg)("h4",{id:"example-5"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: public-ip\n")),(0,r.yg)("p",null,"Or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: public-ip\n options:\n provider: ipgeolocation\n apiKey: xxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-5"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://ipgeolocation.io/privacy.html"},"IPGeoLocation Privacy Policy")," or ",(0,r.yg)("a",{parentName:"em",href:"https://ip-api.com/docs/legal"},"IP-API Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"ip-blacklist"},"IP Blacklist"),(0,r.yg)("p",null,"Notice certain web pages aren't loading? This widget quickly shows which blacklists your IP address (or host, or email) appears on, using data from ",(0,r.yg)("a",{parentName:"p",href:"https://blacklistchecker.com/"},"blacklistchecker.com"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/hX0fp5Z/ip-blacklist.png"})),(0,r.yg)("h4",{id:"options-6"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"ipAddress"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The IP to check. This can also be a domain/ host name or even an email address. If left blank, Dashy will use your current public IP address.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"You can get your free API key from ",(0,r.yg)("a",{parentName:"td",href:"https://blacklistchecker.com/keys"},"blacklistchecker.com"))))),(0,r.yg)("h4",{id:"example-6"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: blacklist-check\n options:\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n ipAddress: 1.1.1.1\n")),(0,r.yg)("h4",{id:"info-6"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free Plan"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://blacklistchecker.com/privacy"},"BlacklistChecker Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"domain-monitor"},"Domain Monitor"),(0,r.yg)("p",null,"Keep an eye on the expiry dates of your domain names, using public whois records fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://whoapi.com/"},"whoapi.com"),". Click the domain name to view additional info, like registrar, name servers and date last updated."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/7XjByG9/domain-monitor.png"})),(0,r.yg)("h4",{id:"options-7"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"domain"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The domain to check")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"You can get your free API key from ",(0,r.yg)("a",{parentName:"td",href:"https://my.whoapi.com/user/signup"},"my.whoapi.com"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showFullInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, the toggle-full-info panel will be open by default")))),(0,r.yg)("h4",{id:"example-7"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: domain-monitor\n options:\n domain: example.com\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n - type: domain-monitor\n options:\n domain: example2.com\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-7"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free Plan (10,000 requests)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://whoapi.com/privacy-policy/"},"WhoAPI Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"crypto-watch-list"},"Crypto Watch List"),(0,r.yg)("p",null,"Keep track of price changes of your favorite crypto assets. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://www.coingecko.com/"},"CoinGecko"),". All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/WtS6jQ8/crypto-prices.png"})),(0,r.yg)("h4",{id:"options-8"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"assets"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of cryptocurrencies, coins and tokens. See ",(0,r.yg)("a",{parentName:"td",href:"https://api.coingecko.com/api/v3/asset_platforms"},"list of supported assets"),". If none are specified, then the top coins by ",(0,r.yg)("inlineCode",{parentName:"td"},"sortBy")," (defaults to market cap) will be returned")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"currency"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The fiat currency to display price in, expressed as an ISO-4217 alpha code (see ",(0,r.yg)("a",{parentName:"td",href:"https://www.iban.com/currency-codes"},"list of currencies"),"). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"USD"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The method of sorting results. Can be ",(0,r.yg)("inlineCode",{parentName:"td"},"marketCap"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"volume")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"alphabetical"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"marketCap"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Number of results to return, useful when no assets are specified. Defaults to either ",(0,r.yg)("inlineCode",{parentName:"td"},"all")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"100"))))),(0,r.yg)("h4",{id:"example-8"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: crypto-watch-list\n options:\n limit: 10\n")),(0,r.yg)("p",null,"Or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: crypto-watch-list\n options:\n currency: GBP\n sortBy: marketCap\n assets:\n - bitcoin\n - ethereum\n - monero\n - cosmos\n - polkadot\n - dogecoin\n")),(0,r.yg)("h4",{id:"info-8"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.coingecko.com/en/privacy"},"CoinGecko Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"crypto-token-price-history"},"Crypto Token Price History"),(0,r.yg)("p",null,"Shows recent price history for a given crypto asset, using price data fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://www.coingecko.com/"},"CoinGecko")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/jr38m6S/crypto-price-history.png"})),(0,r.yg)("h4",{id:"options-9"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"asset"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Name of a crypto asset, coin or token to fetch price data for, see ",(0,r.yg)("a",{parentName:"td",href:"https://api.coingecko.com/api/v3/asset_platforms"},"list of supported assets"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"currency"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The fiat currency to display results in, expressed as an ISO-4217 alpha code (see ",(0,r.yg)("a",{parentName:"td",href:"https://www.iban.com/currency-codes"},"list of currencies"),"). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"USD"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"numDays"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of days of price history to render. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"7"),", min: ",(0,r.yg)("inlineCode",{parentName:"td"},"1"),", max: ",(0,r.yg)("inlineCode",{parentName:"td"},"30")," days")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color")," which inherits dashboard primary color")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))))),(0,r.yg)("h4",{id:"example-9"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: crypto-price-chart\n options:\n asset: bitcoin\n currency: GBP\n numDays: 7\n")),(0,r.yg)("h4",{id:"info-9"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.coingecko.com/en/privacy"},"CoinGecko Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"wallet-balance"},"Wallet Balance"),(0,r.yg)("p",null,"Keep track of your crypto balances and see recent transactions. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://www.blockcypher.com/dev/"},"BlockCypher")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/27HG4nj/wallet-balances.png"})),(0,r.yg)("h4",{id:"options-10"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"coin"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Symbol of coin or asset, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"btc"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"eth")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"doge"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"address"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Address to monitor. This is your wallet's ",(0,r.yg)("strong",{parentName:"td"},"public")," / receiving address")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"network"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"To use a different network, other than mainnet. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"main"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of transactions to display. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"),", set to large number to show all")))),(0,r.yg)("h4",{id:"example-10"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: wallet-balance\n options:\n coin: btc\n address: 3853bSxupMjvxEYfwGDGAaLZhTKxB2vEVC\n")),(0,r.yg)("h4",{id:"info-10"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.blockcypher.com/privacy.html"},"BlockCypher Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"code-stats"},"Code Stats"),(0,r.yg)("p",null,"Display your coding summary. ",(0,r.yg)("a",{parentName:"p",href:"https://codestats.net/"},"Code::Stats")," is a free and open source app that aggregates statistics about your programming activity. Dashy supports both the public instance, as well as self-hosted versions."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/dc0DTBW/code-stats.png"})),(0,r.yg)("h4",{id:"options-11"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your CodeStats username")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If your self-hosting CodeStats, then supply the host name. By default it will use the public hosted instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"monthsToShow"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the number of months to render in the historical data chart. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"6"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideMeta"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide the meta section (username, level, all-time and recent XP)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideHistory"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide the historical calendar heat map")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideLanguages"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide the programming languages pie chart")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideMachines"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide the machines percentage chart")))),(0,r.yg)("h4",{id:"example-11"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: code-stats\n options:\n username: alicia\n")),(0,r.yg)("h4",{id:"info-11"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted or Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://codestats.net/tos#privacy"},"Code::Stats Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"mullvad-status"},"Mullvad Status"),(0,r.yg)("p",null,"Shows your Mullvad VPN connection status, as well as server info. Fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://mullvad.net/en/check/"},"am.i.mullvad.net")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/3BCb2YV/mullvad-check.png"})),(0,r.yg)("h4",{id:"options-12"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No Options.")),(0,r.yg)("h4",{id:"example-12"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: mullvad-status\n")),(0,r.yg)("h4",{id:"info-12"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://mullvad.net/en/help/privacy-policy/"},"Mullvad Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"anonaddy"},"AnonAddy"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://anonaddy.com/"},"AnonAddy")," is a free and open source mail forwarding service. Use it to protect your real email address, by using a different alias for each of your online accounts, and have all emails land in your normal inbox(es). Supports custom domains, email replies, PGP-encryption, multiple recipients and more"),(0,r.yg)("p",null,"This widget display email addresses / aliases from AnonAddy. Click an email address to copy to clipboard, or use the toggle switch to enable/ disable it. Shows usage stats (bandwidth, used aliases etc), as well as total messages received, blocked and sent. Works with both self-hosted and managed instances of AnonAddy."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/ZhfyRdV/anonaddy.png"})),(0,r.yg)("h4",{id:"options-13"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your AnonAddy API Key / Personal Access Token. You can generate this under ",(0,r.yg)("a",{parentName:"td",href:"https://app.anonaddy.com/settings"},"Account Settings"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If your self-hosting AnonAddy, then supply the host name. By default it will use the public hosted instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiVersion"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you're using an API version that is not version ",(0,r.yg)("inlineCode",{parentName:"td"},"v1"),", then specify it here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of emails shown per page. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the sort order for email addresses. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"updated_at"),". Can be either: ",(0,r.yg)("inlineCode",{parentName:"td"},"local_part"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"domain"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"email"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"emails_forwarded"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"emails_blocked"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"emails_replied"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"emails_sent"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"created_at"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"updated_at")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"deleted_at"),". Precede with a ",(0,r.yg)("inlineCode",{parentName:"td"},"-")," character to reverse order.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"searchTerm"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A search term to filter results by, will search the email, description and domain")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableControls"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Prevent any changes being made to account through the widget. User will not be able to enable or disable aliases through UI when this option is set")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideMeta"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Don't show account meta info (forward/ block count, quota usage etc)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideAliases"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Don't show email address / alias list. Will only show account meta info")))),(0,r.yg)("h4",{id:"example-13"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},' - type: anonaddy\n options:\n apiKey: "xxxxxxxxxxxxxxxxxxxxxxxx\\\n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\\n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"\n limit: 5\n sortBy: created_at\n disableControls: true\n')),(0,r.yg)("h4",{id:"info-13"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free for Self-Hosted / Free Plan available on managed instance or $1/month for premium"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted or Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://anonaddy.com/privacy/"},"AnonAddy Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"vulnerability-feed"},"Vulnerability Feed"),(0,r.yg)("p",null,"Keep track of recent security advisories and vulnerabilities, with optional filtering by score, exploits, vendor and product. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/DYJMpjp/vulnerability-feed.png"})),(0,r.yg)("h4",{id:"options-14"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The sorting method. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"publish-date"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"last-update")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"cve-code"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"publish-date"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of results to fetch. Can be between ",(0,r.yg)("inlineCode",{parentName:"td"},"5")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"30"),", defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"minScore"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set, will only display results with a CVE score higher than the number specified. Can be a number between ",(0,r.yg)("inlineCode",{parentName:"td"},"0")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"9.9"),". By default, vulnerabilities of all CVE scores are shown")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hasExploit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", will only show results with active exploits. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"vendorId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only show results from a specific vendor, specified by ID. See ",(0,r.yg)("a",{parentName:"td",href:"https://www.cvedetails.com/vendor-search.php"},"Vendor Search")," for list of vendors. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"23")," (Debian), ",(0,r.yg)("inlineCode",{parentName:"td"},"26")," (Microsoft), ",(0,r.yg)("inlineCode",{parentName:"td"},"23682")," (CloudFlare)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"productId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only show results from a specific app or product, specified by ID. See ",(0,r.yg)("a",{parentName:"td",href:"https://www.cvedetails.com/product-search.php"},"Product Search")," for list of products. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"28125")," (Docker), ",(0,r.yg)("inlineCode",{parentName:"td"},"34622")," (NextCloud), ",(0,r.yg)("inlineCode",{parentName:"td"},"50211")," (Portainer), ",(0,r.yg)("inlineCode",{parentName:"td"},"95391")," (ProtonMail)")))),(0,r.yg)("h4",{id:"example-14"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: cve-vulnerabilities\n")),(0,r.yg)("p",null,"or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: cve-vulnerabilities\n options:\n sortBy: publish-date\n productId: 28125\n hasExploit: false\n minScore: 5\n limit: 30\n")),(0,r.yg)("h4",{id:"info-14"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.cvedetails.com/privacy.php"},"CVE Details Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"exchange-rates"},"Exchange Rates"),(0,r.yg)("p",null,"Display current FX rates in your native currency. Hover over a row to view more info, or click to show rates in that currency."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/fMdyLTB/exchange-rates.png"})),(0,r.yg)("h4",{id:"options-15"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"inputCurrency"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The base currency to show results in. Specified as a 3-letter ISO-4217 code, see ",(0,r.yg)("a",{parentName:"td",href:"https://www.exchangerate-api.com/docs/supported-currencies"},"here")," for the full list of supported currencies, and their symbols")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"outputCurrencies"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"List or currencies to show results for. Specified as a 3-letter ISO-4217 code, see ",(0,r.yg)("a",{parentName:"td",href:"https://www.exchangerate-api.com/docs/supported-currencies"},"here")," for the full list of supported currencies, and their symbols")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"API key for ",(0,r.yg)("a",{parentName:"td",href:"https://www.exchangerate-api.com/"},"exchangerate-api.com"),", usually a 24-digit alpha-numeric string. You can sign up for a free account ",(0,r.yg)("a",{parentName:"td",href:"https://app.exchangerate-api.com/sign-up"},"here"))))),(0,r.yg)("h4",{id:"example-15"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: exchange-rates\n options:\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxx\n inputCurrency: GBP\n outputCurrencies:\n - USD\n - JPY\n - HKD\n - KPW\n")),(0,r.yg)("h4",{id:"info-15"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 100,000 requests/ month)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.exchangerate-api.com/terms"},"ExchangeRateAPI Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"public-holidays"},"Public Holidays"),(0,r.yg)("p",null,"Counting down to the next day off work? This widget displays upcoming public holidays for your country. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"http://kayaposoft.com/enrico/"},"Enrico")),(0,r.yg)("p",null,"Note, config for this widget is case-sensetive (see ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/1268"},"#1268"),")"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/VC6fZqn/public-holidays.png"})),(0,r.yg)("h4",{id:"options-16"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"country"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The country to fetch holiday data for, specified as a country code, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"GB")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"US"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"state"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"restrict a country to a specific state defined by ",(0,r.yg)("a",{parentName:"td",href:"https://en.wikipedia.org/wiki/ISO_3166-2"},"ISO_3166-2"),", e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"LND"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"holidayType"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The type of holidays to fetch. Can be: ",(0,r.yg)("inlineCode",{parentName:"td"},"all"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"public_holiday"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"observance"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"school_holiday"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"other_day")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"extra_working_day"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"public_holiday"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"monthsToShow"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of months in advance to show. Min: ",(0,r.yg)("inlineCode",{parentName:"td"},"1"),", max: ",(0,r.yg)("inlineCode",{parentName:"td"},"24"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"12"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lang"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The language in which the events should be. Usually local languages and english are available. Default to first available in the country. e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"en")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"fr"),".")))),(0,r.yg)("h4",{id:"example-16"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: public-holidays\n options:\n country: GB\n region: LND\n holidayType: all\n monthsToShow: 12\n lang: en\n")),(0,r.yg)("h4",{id:"info-16"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jurajmajer/enrico"},"jurajmajer/enrico"),") or Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"covid-19-status"},"Covid-19 Status"),(0,r.yg)("p",null,"Keep track of the current COVID-19 status. Optionally also show cases by country, and a time-series chart. Uses live data from various sources, computed by ",(0,r.yg)("a",{parentName:"p",href:"https://disease.sh/"},"disease.sh")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/7XjbyRg/covid-19-status.png?"})),(0,r.yg)("h4",{id:"options-17"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showChart"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Also display a time-series chart showing number of recent cases")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showCountries"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Also display a list of cases per country")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"numDays"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify number of days worth of history to render on the chart")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"countries"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of countries to display, specified by their ",(0,r.yg)("a",{parentName:"td",href:"https://www.iso.org/obp/ui"},"ISO-3 codes"),". Leave blank to show all, sorted by most cases. ",(0,r.yg)("inlineCode",{parentName:"td"},"showCountries")," must be set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If showing all countries, set a limit for number of results to return. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"),", no maximum")))),(0,r.yg)("h4",{id:"example-17"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: covid-stats\n")),(0,r.yg)("p",null,"Or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: covid-stats\n options:\n showChart: true\n showCountries: true\n countries:\n - GBR\n - USA\n - IND\n - RUS\n")),(0,r.yg)("h4",{id:"info-17"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/disease-sh/api"},"disease-sh/api"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Conditions"),": ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/disease-sh/api/blob/master/TERMS.md"},"Terms of Use"))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"sports-scores"},"Sports Scores"),(0,r.yg)("p",null,"Show recent scores and upcoming matches from your favourite sports team. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://www.thesportsdb.com/"},"TheSportsDB.com"),". From the UI, you can click any other team to view their scores and upcoming games, or click a league name to see all teams."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/8XhXGkN/sports-scores.png"})),(0,r.yg)("h4",{id:"options-18"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"teamId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The ID of a team to fetch scores from. You can search for your team on the ",(0,r.yg)("a",{parentName:"td",href:"https://www.thesportsdb.com/teams_main.php"},"Teams Page"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"leagueId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Alternatively, provide a league ID to fetch all games from. You can find the ID on the ",(0,r.yg)("a",{parentName:"td",href:"https://www.thesportsdb.com/Sport/Leagues"},"Leagues Page"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"pastOrFuture"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set to ",(0,r.yg)("inlineCode",{parentName:"td"},"past")," to show scores for recent games, or ",(0,r.yg)("inlineCode",{parentName:"td"},"future")," to show upcoming games. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"past"),". You can change this within the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally specify your API key, which you can sign up for at ",(0,r.yg)("a",{parentName:"td",href:"https://www.thesportsdb.com/"},"TheSportsDB.com"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"To limit output to a certain number of matches, defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"15"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideImage"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," to not render the team / match banner image, defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))))),(0,r.yg)("h4",{id:"example-18"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: sports-scores\n options:\n teamId: 133636\n")),(0,r.yg)("h4",{id:"info-18"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 30 requests / minute, limited endpoints)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"news-headlines"},"News Headlines"),(0,r.yg)("p",null,"Displays the latest news, click to read full article. Date is fetched from various news sources using ",(0,r.yg)("a",{parentName:"p",href:"https://currentsapi.services/en"},"Currents API")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/6NDWW0z/news-headlines.png"})),(0,r.yg)("h4",{id:"options-19"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your API key for CurrentsAPI. This is free, and you can ",(0,r.yg)("a",{parentName:"td",href:"https://currentsapi.services/en/register"},"get one here"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"country"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Fetch news only from a certain country or region. Specified as a country code, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"GB")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"US"),". See ",(0,r.yg)("a",{parentName:"td",href:"https://api.currentsapi.services/v1/available/regions"},"here")," for a list of supported regions")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"category"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only return news from within a given category, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"sports"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"programming"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"world"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"science"),". The ",(0,r.yg)("a",{parentName:"td",href:"https://api.currentsapi.services/v1/available/categories"},"following categories")," are supported")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lang"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the language for returned articles as a 2-digit ISO code (limited article support). The ",(0,r.yg)("a",{parentName:"td",href:"https://api.currentsapi.services/v1/available/languages"},"following languages")," are supported, defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"en"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"count"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of results. Can be between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"200"),", defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"keywords"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only return articles that contain an exact match within their title or description")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideImages"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", then article image thumbnails will not be displayed")))),(0,r.yg)("h4",{id:"example-19"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: news-headlines\n options:\n apiKey: xxxxxxx\n category: world\n")),(0,r.yg)("h4",{id:"info-19"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 600 requests / day)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://currentsapi.services/privacy"},"CurrentsAPI Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"tfl-status"},"TFL Status"),(0,r.yg)("p",null,"Shows real-time tube status of the London Underground. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/LRDhXDn/tfl-status.png"})),(0,r.yg)("h4",{id:"options-20"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showAll"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default, details for lines with a Good Service are not visible, but you can click More Details to see all. Setting this option to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," will show all lines on initial page load")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortAlphabetically"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default lines are sorted by current status, set this option to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," to instead sort them alphabetically")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"linesToShow"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default all lines are shown. If you're only interested in the status of a few lines, then pass in an array of lines to show, specified by name")))),(0,r.yg)("h4",{id:"example-20"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: tfl-status\n")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: tfl-status\n options:\n showAll: true\n sortAlphabetically: true\n linesToShow:\n - District\n - Jubilee\n - Central\n")),(0,r.yg)("h4",{id:"info-20"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://tfl.gov.uk/corporate/privacy-and-cookies/"},"TFL Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"stock-price-history"},"Stock Price History"),(0,r.yg)("p",null,"Shows recent price history for a given publicly-traded stock or share"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/XZHRb4f/stock-price.png"})),(0,r.yg)("h4",{id:"options-21"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"API key for ",(0,r.yg)("a",{parentName:"td",href:"https://www.alphavantage.co/"},"Alpha Vantage"),", you can get a free API key ",(0,r.yg)("a",{parentName:"td",href:"https://www.alphavantage.co/support/#api-key"},"here"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"stock"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The stock symbol for the asset to fetch data for")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"priceTime"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The time to fetch price for. Can be ",(0,r.yg)("inlineCode",{parentName:"td"},"high"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"low"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"open")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"close"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"high"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color")," which inherits dashboard primary color")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))))),(0,r.yg)("h4",{id:"example-21"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: stock-price-chart\n options:\n stock: NET\n apiKey: PGUWSWD6CZTXMT8N\n")),(0,r.yg)("h4",{id:"info-21"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 500 requests/day)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.alphavantage.co/privacy/"},"AlphaVantage Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"eth-gas-prices"},"ETH Gas Prices"),(0,r.yg)("p",null,"Renders the current Gas cost of transactions on the Ethereum network (in both GWEI and USD), along with recent historical prices. Useful for spotting a good time to transact. Uses data from ",(0,r.yg)("a",{parentName:"p",href:"https://ethgas.watch/"},"ethgas.watch")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/LhHfQyp/eth-gas-prices.png"})),(0,r.yg)("h4",{id:"options-22"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No config options.")),(0,r.yg)("h4",{id:"example-22"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: eth-gas-prices\n")),(0,r.yg)("h4",{id:"info-22"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/wslyvh/ethgaswatch"},"wslyvh/ethgaswatch"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"joke"},"Joke"),(0,r.yg)("p",null,"Renders a programming or generic joke. Data is fetched from the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Sv443/JokeAPI"},"JokesAPI")," by @Sv443. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/sQJGkyR/joke.png"})),(0,r.yg)("h4",{id:"options-23"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"category"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set the category of jokes to return. Use a string to specify a single category, or an array to pass in multiple options. Available options are: ",(0,r.yg)("inlineCode",{parentName:"td"},"all"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"programming"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"pun"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"dark"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"spooky"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"christmas")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"misc"),". An up-to-date list of supported categories can be found ",(0,r.yg)("a",{parentName:"td",href:"https://v2.jokeapi.dev/categories"},"here"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"all"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"safeMode"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", to prevent the fetching of any NSFW jokes. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"language"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the language for returned jokes. The following languages are supported: ",(0,r.yg)("inlineCode",{parentName:"td"},"en"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"cs"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"de"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"es"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"fr")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"pt"),", and an up-to-date list of supported languages can be found ",(0,r.yg)("a",{parentName:"td",href:"https://v2.jokeapi.dev/languages"},"here"),". By default, your system language will be used, if it's supported, otherwise English")))),(0,r.yg)("h4",{id:"example-23"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: joke\n options:\n safeMode: true\n language: en\n category: Programming\n")),(0,r.yg)("h4",{id:"info-23"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Sv443/JokeAPI"},"Sv443/JokeAPI"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://sv443.net/privacypolicy/en"},"SV443's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"xkcd-comics"},"XKCD Comics"),(0,r.yg)("p",null,"Have a laugh with the daily comic from ",(0,r.yg)("a",{parentName:"p",href:"https://xkcd.com/"},"XKCD"),". A classic webcomic website covering everything from Linux, math, romance, science and language. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/kqV68hy/xkcd-comic.png"})),(0,r.yg)("h4",{id:"options-24"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"comic"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string / number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Choose which comic to display. Set to either ",(0,r.yg)("inlineCode",{parentName:"td"},"random"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"latest")," or the series number of a specific comic, like ",(0,r.yg)("inlineCode",{parentName:"td"},"627"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"latest"))))),(0,r.yg)("h4",{id:"example-24"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: xkcd-comic\n options:\n comic: latest\n")),(0,r.yg)("h4",{id:"info-24"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"flight-data"},"Flight Data"),(0,r.yg)("p",null,"Displays airport departure and arrival flights, using data from ",(0,r.yg)("a",{parentName:"p",href:"https://www.aerodatabox.com/"},"AeroDataBox"),". Useful if you live near an airport and often wonder where the flight overhead is going to. Hover over a row for more flight data."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/yPMBJSY/flight-data.png"})),(0,r.yg)("h4",{id:"options-25"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"airport"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The airport to show flight data from. Should be specified as a 4-character ICAO-code, a full list of which can be found ",(0,r.yg)("a",{parentName:"td",href:"https://en.wikipedia.org/wiki/ICAO_airport_code"},"here")," (example: ",(0,r.yg)("inlineCode",{parentName:"td"},"KBJC")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"EGKK"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A valid ",(0,r.yg)("a",{parentName:"td",href:"https://rapidapi.com/"},"RapidAPI")," Key, with ",(0,r.yg)("a",{parentName:"td",href:"https://rapidapi.com/aerodatabox/api/aerodatabox/"},"AeroDataBox")," enabled (check in your ",(0,r.yg)("a",{parentName:"td",href:"https://rapidapi.com/developer/billing/subscriptions-and-usage"},"Subscription Dashboard"),"). This API is free to sign up for and use")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"For busy airports, you may wish to limit the number of results visible")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"direction"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default, both departure and arrival flights will be fetched, if you would like to only show flights in one direction, set this to wither ",(0,r.yg)("inlineCode",{parentName:"td"},"departure")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"arrival"))))),(0,r.yg)("h4",{id:"example-25"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: flight-data\n options:\n airport: EGLC\n apiKey: XXXXX\n limit: 12\n direction: all\n")),(0,r.yg)("h4",{id:"info-25"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 150 requests / month)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.aerodatabox.com/#h.p_CXtIYZWF_WQd"},"AeroDataBox")," and ",(0,r.yg)("a",{parentName:"em",href:"https://rapidapi.com/privacy/"},"RapidAPI Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"astronomy-picture-of-the-day"},"Astronomy Picture of the Day"),(0,r.yg)("p",null,"Show the NASA Astronomy Picture of the Day. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://apod.nasa.gov/apod/"},"APOD")," using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/lissy93/go-apod"},"@Lissy93/go-apod")," / hosted at ",(0,r.yg)("a",{parentName:"p",href:"https://apod.as93.net/"},"apod.as93.net"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/ZMkgLFK/apod.png"})),(0,r.yg)("h4",{id:"options-26"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No config options.")),(0,r.yg)("h4",{id:"example-26"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: apod\n")),(0,r.yg)("h4",{id:"info-26"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/lissy93/go-apod"},"@Lissy93/go-apod"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.nasa.gov/about/highlights/HP_Privacy.html"},"NASA's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"github-trending"},"GitHub Trending"),(0,r.yg)("p",null,"Displays currently trending projects on GitHub. Optionally specify a language and time-frame. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/gh-trending-no-cors"},"Lissy93/gh-trending-no-cors")," using the GitHub API. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/BGy7Q3g/github-trending.png"})),(0,r.yg)("h4",{id:"options-27"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lang"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A programming language to fetch trending repos from that category. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"javascript")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"go"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"since"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The timeframe to use when calculating trends. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"daily"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"weekly")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"monthly"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"daily"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally limit the number of results. Max ",(0,r.yg)("inlineCode",{parentName:"td"},"25"),", default is ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))))),(0,r.yg)("h4",{id:"example-27"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: github-trending-repos\n options:\n limit: 8\n since: weekly\n")),(0,r.yg)("h4",{id:"info-27"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Lissy93/gh-trending-no-cors"},"Lissy93/gh-trending-no-cors"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://docs.github.com/en/github/site-policy/github-privacy-statement"},"GitHub's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"github-profile-stats"},"GitHub Profile Stats"),(0,r.yg)("p",null,"Display stats from your GitHub profile, using embedded cards from ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/anuraghazra/github-readme-stats"},"anuraghazra/github-readme-stats")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/L0K1zNN/github-profile-stats.png"})),(0,r.yg)("h4",{id:"options-28"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The GitHub username to fetch info for. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"lissy93"),". (Not required if ",(0,r.yg)("inlineCode",{parentName:"td"},"hideProfileCard")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"hideLanguagesCard")," are both set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideProfileCard"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the users profile card will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideLanguagesCard"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the users top languages card will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"repos"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you'd like to also display stats for some GitHub repositories, then add an array or repo names here. Specified as ",(0,r.yg)("inlineCode",{parentName:"td"},"[username]/[repo-name]"),", e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"lissy93/dashy"))))),(0,r.yg)("h4",{id:"example-28"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: github-profile-stats\n options:\n username: Lissy93\n hideLanguagesCard: true\n repos:\n - lissy93/dashy\n - lissy93/personal-security-checklist\n - lissy93/twitter-sentiment-visualisation\n")),(0,r.yg)("h4",{id:"info-28"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/anuraghazra/github-readme-stats"},"anuraghazra/github-readme-stats"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://docs.github.com/en/github/site-policy/github-privacy-statement"},"GitHub's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"healthchecks-status"},"HealthChecks Status"),(0,r.yg)("p",null,"Display status of one or more HealthChecks project(s). Works with healthchecks.io and your selfhosted instance."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/W5dP6VN/Bildschirm-foto-2023-01-07-um-11-07-11.png"})),(0,r.yg)("h4",{id:"options-29"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional"),(0,r.yg)("td",{parentName:"tr",align:null},"The base url of your instance, default is ",(0,r.yg)("inlineCode",{parentName:"td"},"https://healthchecks.io"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"One or more API keys for your healthcheck projects. (Read-only works fine)")))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: HealthChecks\n options:\n host: https://healthcheck.your-domain.de\n apiKey: \n - abcdefg...\n - zxywvu...\n")),(0,r.yg)("h4",{id:"info-29"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free / Paid / Self-hosted "),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/healthchecks/healthchecks"},"healthchecks/healthchecks"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://healthchecks.io/privacy/"},"Healthchecks.io Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"hackernews-trending"},"Hackernews Trending"),(0,r.yg)("p",null,"Display new and trending Posts from Hackernews"),(0,r.yg)("h4",{id:"options-30"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"stories"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"HN Stories to display defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"topstories"),". Options are: ",(0,r.yg)("inlineCode",{parentName:"td"},"beststories"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"topstories")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"newstories"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"int")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The size of the list of Posts to show.")))),(0,r.yg)("h5",{id:"example-29"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: hackernews-trending\n options:\n stories: newstories\n limit: 10\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"mvg-departure"},"MVG Departure"),(0,r.yg)("p",null,"Display departure time of a MVG (M\xfcnchner Verkehrs Gesellschaft) station."),(0,r.yg)("p",null,"From ",(0,r.yg)("a",{parentName:"p",href:"https://www.mvg.de/impressum.html"},"https://www.mvg.de/impressum.html"),":"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"[...]"," Die Verarbeitung unserer Inhalte oder Daten durch Dritte erfordert unsere ausdr\xfcckliche Zustimmung. F\xfcr private, nicht-kommerzielle Zwecke, wird eine gem\xe4\xdfigte Nutzung ohne unsere ausdr\xfcckliche Zustimmung geduldet. Jegliche Form von Data-Mining stellt keine gem\xe4\xdfigte Nutzung dar.","[...]")),(0,r.yg)("p",null,"In other words: Private, noncomercial, moderate use of the API is tolerated. They don\u2019t consider data mining as moderate use. (This is not a legal advice)"),(0,r.yg)("h4",{id:"options-31"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"location"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The name of the location (exact) or the location id, startin with ",(0,r.yg)("inlineCode",{parentName:"td"},"de:09162:"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"integer")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit number of entries, defaults to 10.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A custom title to be displayed.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"header"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"bool")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Shall the title be shown?")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.line"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for given line(s).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.product"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for specific product (TRAM, UBAHN, SBAHN, BUS).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.destination"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for specific destination(s)")))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: mvg\n options:\n location: Marienplatz\n limit: 5\n")),(0,r.yg)("h4",{id:"info-30"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free / Private use only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": ",(0,r.yg)("a",{parentName:"li",href:"https://mvg.de"},"MVG")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.mvg.de/datenschutz-mvg.html"},"MVG Datenschutz")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"mvg-connection"},"MVG Connection"),(0,r.yg)("p",null,"Display the next connection for two addresses/coordinates, stations or POI within Munich using MVG MVG (M\xfcnchner Verkehrs Gesellschaft)."),(0,r.yg)("p",null,"From ",(0,r.yg)("a",{parentName:"p",href:"https://www.mvg.de/impressum.html"},"https://www.mvg.de/impressum.html"),":"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"[...]"," Die Verarbeitung unserer Inhalte oder Daten durch Dritte erfordert unsere ausdr\xfcckliche Zustimmung. F\xfcr private, nicht-kommerzielle Zwecke, wird eine gem\xe4\xdfigte Nutzung ohne unsere ausdr\xfcckliche Zustimmung geduldet. Jegliche Form von Data-Mining stellt keine gem\xe4\xdfigte Nutzung dar.","[...]")),(0,r.yg)("p",null,"In other words: Private, noncomercial, moderate use of the API is tolerated. They don\u2019t consider data mining as moderate use. (This is not a legal advice)"),(0,r.yg)("h4",{id:"options-32"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"origin"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Origin of the connection.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"destination"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Destination of the connection.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A custom title to be displayed.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"header"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"bool")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Shall the title be shown?")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.line"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for given line(s).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.product"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for specific product (TRAM, UBAHN, SBAHN, BUS).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.destination"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for specific destination(s)")))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: mvg-connection\n options:\n from: Marienplatz\n from: Dachauer Stra\xdfe 123\n header: true\n filters:\n product: [UBAHN]\n line: [U1,U2,U4,U5]\n\n")),(0,r.yg)("h4",{id:"info-31"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free / Private use only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": ",(0,r.yg)("a",{parentName:"li",href:"https://mvg.de"},"MVG")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.mvg.de/datenschutz-mvg.html"},"MVG Datenschutz")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"custom-search"},"Custom search"),(0,r.yg)("p",null,"Allows web search using multiple user-defined search engines and other websites."),(0,r.yg)("h4",{id:"options-33"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"engines"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"required"),(0,r.yg)("td",{parentName:"tr",align:null},"An array of search engine objects. Each search engine object should have two required properties: ",(0,r.yg)("strong",{parentName:"td"},"title")," and ",(0,r.yg)("strong",{parentName:"td"},"url"),". See the example below.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"placeholder"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"Placeholder text in the search box.")))),(0,r.yg)("h4",{id:"notes"},"Notes"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The first search engine in the engines array will be treated as the default search engine, and used when the user presses ",(0,r.yg)("inlineCode",{parentName:"li"},"Enter")," in the search box."),(0,r.yg)("li",{parentName:"ul"},"Popup blockers can interfere with opening a new search window.")),(0,r.yg)("h4",{id:"example-30"},"Example"),(0,r.yg)("p",null,"This widget allows searching multiple search engines from dashy."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: 'custom-search'\n options:\n placeholder: Search for something using the buttons below\n engines:\n - title: SearXNG\n url: https://searx.lan/?q=\n - title: Quant\n url: https://www.qwant.com/?q=\n - title: Bing Web\n url: http://www.bing.com/search?q=\n - title: Bing Images\n url: http://www.bing.com/images/search?q=\n - title: Bing Maps\n url: http://www.bing.com/maps/search?q=\n - title: Yandex\n url: https://www.yandex.com/search/?text=\n - title: Passmark\n url: https://www.passmark.com/search/zoomsearch.php?zoom_query=\n - title: IMDB\n url: http://www.imdb.com/find?q=\n")),(0,r.yg)("h4",{id:"info-32"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Not needed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free "),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": user defined"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": depends on the user defined search engines.")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"rescuetime-overview"},"RescueTime Overview"),(0,r.yg)("p",null,"Show an overview of how you have spent your time for the current day."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/bvx3PQM/rescuetime.png"})),(0,r.yg)("h4",{id:"options-34"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"required"),(0,r.yg)("td",{parentName:"tr",align:null},"The API-Key generated in the RescueTime UI.")))),(0,r.yg)("h4",{id:"example-31"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: rescue-time\n useProxy: true\n options:\n apiKey: abcdefghijkl_mnop\n")),(0,r.yg)("h4",{id:"info-33"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Depends on user subscription "),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": ",(0,r.yg)("a",{parentName:"li",href:"https://www.rescuetime.com"},"RescueTime")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.rescuetime.com/privacy"},"RescueTime Privacy")))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"self-hosted-services-widgets"},"Self-Hosted Services Widgets"),(0,r.yg)("h3",{id:"system-info"},"System Info"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.mvg.de/datenschutz-mvg.html"},"MVG Datenschutz")),"\nDisplays info about the server which Dashy is hosted on. Includes user + host, operating system, uptime and basic memory & load data."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/rvDPBDF/system-info.png"})),(0,r.yg)("h4",{id:"options-35"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No config options.")),(0,r.yg)("h4",{id:"example-32"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: system-info\n")),(0,r.yg)("h4",{id:"info-34"},"Info"),(0,r.yg)("p",null,"No external data requests made"),(0,r.yg)("p",null,"Note that this widget is not available if you are running Dashy in a container or VM. Instead you can use the ",(0,r.yg)("a",{parentName:"p",href:"#system-resource-monitoring"},"System Monitoring")," widgets to display stats from the host system instead."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cron-monitoring-health-checks"},"Cron Monitoring (Health Checks)"),(0,r.yg)("p",null,"Cron job monitoring using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/healthchecks/healthchecks"},"Health Checks"),". Both managed and self-hosted instances are supported."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/Ptf2kwm/health-checks.png"})),(0,r.yg)("h4",{id:"options-36"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A read-only API key for the project to monitor. You can generate this by selecting a Project --\x3e Settings --\x3e API Access. Note that you must generate a separate key for each project")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you're self-hosting, or using any instance other than the official (healthchecks.io), you will need to specify the host address. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"https://healthchecks.example.com")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"http://cron-monitoing.local"))))),(0,r.yg)("h4",{id:"example-33"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: health-checks\n options:\n apiKey: XXXXXXXXX\n")),(0,r.yg)("h4",{id:"info-35"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 20 services, or self-host for unlimited)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/healthchecks/healthchecks"},"GitHub - HealthChecks"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://healthchecks.io/privacy/"},"Health-Checks Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cpu-history-netdata"},"CPU History (NetData)"),(0,r.yg)("p",null,"Pull recent CPU usage history from NetData."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/ZdyR5nJ/nd-cpu-history.png"})),(0,r.yg)("h4",{id:"options-37"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your NetData instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," / ",(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value(s) as hex codes. ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColor")," is a single value (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color"),"), whereas ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColors")," is an array of colors")))),(0,r.yg)("h4",{id:"example-34"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nd-cpu-history\n options:\n host: http://192.168.1.1:19999\n")),(0,r.yg)("h4",{id:"info-36"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/netdata/netdata"},"GitHub - NetData"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.netdata.cloud/data-privacy/"},"NetData Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"memory-history-netdata"},"Memory History (NetData)"),(0,r.yg)("p",null,"Pull recent system RAM usage from NetData, and show as a breakdown of different categories."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/2dsSWnk/nd-memory-history.png"})),(0,r.yg)("h4",{id:"options-38"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your NetData instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," / ",(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value(s) as hex codes. ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColor")," is a single value (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color"),"), whereas ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColors")," is an array of colors")))),(0,r.yg)("h4",{id:"example-35"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nd-ram-history\n options:\n host: http://192.168.1.1:19999\n")),(0,r.yg)("h4",{id:"info-37"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/netdata/netdata"},"GitHub - NetData"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.netdata.cloud/data-privacy/"},"NetData Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"load-history-netdata"},"Load History (NetData)"),(0,r.yg)("p",null,"Pull recent load usage in 1, 5 and 15 minute intervals, from NetData."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/qR9C2tJ/nd-load-history.png"})),(0,r.yg)("h4",{id:"options-39"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your NetData instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," / ",(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value(s) as hex codes. ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColor")," is a single value (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color"),"), whereas ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColors")," is an array of colors")))),(0,r.yg)("h4",{id:"example-36"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nd-load-history\n options:\n host: http://192.168.1.1:19999\n")),(0,r.yg)("h4",{id:"info-38"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/netdata/netdata"},"GitHub - NetData"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.netdata.cloud/data-privacy/"},"NetData Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"pi-hole-stats"},"Pi Hole Stats"),(0,r.yg)("p",null,"Displays the number of queries blocked by ",(0,r.yg)("a",{parentName:"p",href:"https://pi-hole.net/"},"Pi-Hole"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/zftCLJN/pi-hole-stats.png"})),(0,r.yg)("h4",{id:"options-40"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your Pi-Hole instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideStatus"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideChart"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide any of the three parts of the widget")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your Pi-Hole web password. It is ",(0,r.yg)("strong",{parentName:"td"},"NOT")," your pi-hole admin interface or server password. It can be found in ",(0,r.yg)("inlineCode",{parentName:"td"},"/etc/pihole/setupVars.conf"),", and is a 64-character located on the line that starts with ",(0,r.yg)("inlineCode",{parentName:"td"},"WEBPASSWORD"))))),(0,r.yg)("h4",{id:"example-37"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: pi-hole-stats\n options:\n hostname: http://192.168.130.1\n apiKey: xxxxxxxxxxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-39"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pi-hole/pi-hole"},"GitHub - Pi-hole"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://pi-hole.net/privacy/"},"Pi-Hole Privacy Guide")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"pi-hole-queries"},"Pi Hole Queries"),(0,r.yg)("p",null,"Shows top queries that were blocked and allowed by ",(0,r.yg)("a",{parentName:"p",href:"https://pi-hole.net/"},"Pi-Hole"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/pXR0bdQ/pi-hole-queries.png"})),(0,r.yg)("h4",{id:"options-41"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your Pi-Hole instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your Pi-Hole web password. It is ",(0,r.yg)("strong",{parentName:"td"},"NOT")," your pi-hole admin interface or server password. It can be found in ",(0,r.yg)("inlineCode",{parentName:"td"},"/etc/pihole/setupVars.conf"),", and is a 64-character located on the line that starts with ",(0,r.yg)("inlineCode",{parentName:"td"},"WEBPASSWORD"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"count"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of queries to display. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))))),(0,r.yg)("h4",{id:"example-38"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: pi-hole-top-queries\n options:\n hostname: https://pi-hole.local\n apiKey: xxxxxxxxxxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-40"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pi-hole/pi-hole"},"GitHub - Pi-hole"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://pi-hole.net/privacy/"},"Pi-Hole Privacy Guide")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"pi-hole-recent-traffic"},"Pi Hole Recent Traffic"),(0,r.yg)("p",null,"Shows number of recent traffic, using allowed and blocked queries from ",(0,r.yg)("a",{parentName:"p",href:"https://pi-hole.net/"},"Pi-Hole")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/7kdxxwx/pi-hole-recent-queries.png"})),(0,r.yg)("h4",{id:"options-42"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your Pi-Hole instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your Pi-Hole web password. It is ",(0,r.yg)("strong",{parentName:"td"},"NOT")," your pi-hole admin interface or server password. It can be found in ",(0,r.yg)("inlineCode",{parentName:"td"},"/etc/pihole/setupVars.conf"),", and is a 64-character located on the line that starts with ",(0,r.yg)("inlineCode",{parentName:"td"},"WEBPASSWORD"))))),(0,r.yg)("h4",{id:"example-39"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: pi-hole-traffic\n options:\n hostname: https://pi-hole.local\n apiKey: xxxxxxxxxxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-41"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pi-hole/pi-hole"},"GitHub - Pi-hole"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://pi-hole.net/privacy/"},"Pi-Hole Privacy Guide")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"stat-ping-statuses"},"Stat Ping Statuses"),(0,r.yg)("p",null,"Displays the current and recent uptime of your running services, via a self-hosted instance of ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/statping/statping"},"StatPing")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"300",src:"https://i.ibb.co/Fq7JDjQ/stat-ping.png"})),(0,r.yg)("h4",{id:"options-43"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your StatPing instance, without a trailing slash")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"groupId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional"),(0,r.yg)("td",{parentName:"tr",align:null},"If provided, only Services in the given group are displayed. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"0")," in which case all services are displayed.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showChart"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional"),(0,r.yg)("td",{parentName:"tr",align:null},"If provided and ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," then charts are not displayed. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional"),(0,r.yg)("td",{parentName:"tr",align:null},"If provided and ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," then information summaries are not displayed. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),".")))),(0,r.yg)("h4",{id:"example-40"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: stat-ping\n options:\n hostname: http://192.168.130.1:8080\n")),(0,r.yg)("p",null,"or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: stat-ping\n options:\n hostname: http://192.168.130.1:8080\n groupId: 3\n showChart: false\n showInfo: false\n")),(0,r.yg)("p",null,"You can use multiple StatPing widgets with different ",(0,r.yg)("inlineCode",{parentName:"p"},"groupId"),"s."),(0,r.yg)("p",null,"Note, the Group Id is not directly visible in StatPing UI, you can inspect the group select HTML element or the API response to find out."),(0,r.yg)("h4",{id:"info-42"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/statping/statping"},"GitHub - StatPing"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://docs.statping.com/"},"StatPing Docs")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"synology-download-station"},"Synology Download Station"),(0,r.yg)("p",null,"Displays the current downloads/torrents tasks of your Synology NAS"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/N2kKWTN/image.png"})),(0,r.yg)("h4",{id:"options-44"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your Synology NAS, without a trailing slash")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The username of a user on your synology NAS. You will see only this user download station tasks if he is not part of the administrator group. Currently don't support OTP protected accounts.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The password of the account specified above.")))),(0,r.yg)("h4",{id:"example-41"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: synology-download\n options:\n hostname: http://192.168.1.1:8080\n username: dashy\n password: totally-secure-password\n\n\n")),(0,r.yg)("h4",{id:"info-43"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://www.synology.com/en-us"},"Synology"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.synology.com/en-us/company/legal/privacy"},"Synology Privacy Statement")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adguard-home-block-stats"},"AdGuard Home Block Stats"),(0,r.yg)("p",null,"Fetches data from your ",(0,r.yg)("a",{parentName:"p",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home")," instance, and\ndisplays total number of allowed and blocked queries, plus a pie chart showing breakdown by block type."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/qgkcxsN/adguard-block-percent-2.png"})),(0,r.yg)("h4",{id:"options-45"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your AdGuard Home instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your username here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your password here")))),(0,r.yg)("h4",{id:"example-42"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: adguard-stats\n useProxy: true\n options:\n hostname: http://127.0.0.1\n username: admin\n password: test\n")),(0,r.yg)("h4",{id:"info-44"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://adguard.com/en/privacy.html"},"AdGuard Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adguard-home-filters"},"AdGuard Home Filters"),(0,r.yg)("p",null,"Fetches data from your ",(0,r.yg)("a",{parentName:"p",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home")," instance, to display the current status of each of your filter lists. Includes filter name, last updated, number of items, and a link to the list."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/WsJkf5g/adguard-filters-list.png"})),(0,r.yg)("h4",{id:"options-46"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your AdGuard Home instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your username here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your password here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showOnOffStatusOnly"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", will only show aggregated AdGuard filter status (on/off), instead of a list of filters")))),(0,r.yg)("h4",{id:"example-43"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: adguard-filter-status\n useProxy: true\n options:\n hostname: http://127.0.0.1\n username: admin\n password: test\n showOnOffStatusOnly: false\n")),(0,r.yg)("h4",{id:"info-45"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://adguard.com/en/privacy.html"},"AdGuard Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adguard-home-dns-info"},"AdGuard Home DNS Info"),(0,r.yg)("p",null,"Fetches data from your ",(0,r.yg)("a",{parentName:"p",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home")," instance, and displays the current status (Enabled / Disabled) of AdGuard DNS. Click show more to view detailed info, including upstream DNS provider, active ports, and the status of DNSSEC, EDNS CS, PTR and IPv6."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/G0JngBb/adguard-dns-info.png"})),(0,r.yg)("h4",{id:"options-47"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your AdGuard Home instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your username here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your password here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showFullInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),', the full DNS info will be shown by default, without having to click "Show Info"')))),(0,r.yg)("h4",{id:"example-44"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: adguard-dns-info\n useProxy: true\n options:\n hostname: http://127.0.0.1\n username: admin\n password: test\n showFullInfo: false\n")),(0,r.yg)("h4",{id:"info-46"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://adguard.com/en/privacy.html"},"AdGuard Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adguard-home-top-domains"},"AdGuard Home Top Domains"),(0,r.yg)("p",null,"Fetches data from your ",(0,r.yg)("a",{parentName:"p",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home")," instance, and displays a list of the most queried, and most blocked domains."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/qRhYYTk/adguard-top-domains.png"})),(0,r.yg)("h4",{id:"options-48"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your AdGuard Home instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your username here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your password here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the number of results to show, between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"100"),", defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideBlockedDomains"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Don't show the blocked domains list (queried domains only)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideQueriedDomains"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Don't show the queried domains list (blocked domains only)")))),(0,r.yg)("h4",{id:"example-45"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: adguard-top-domains\n useProxy: true\n options:\n hostname: http://127.0.0.1\n username: admin\n password: test\n limit: 10\n")),(0,r.yg)("h4",{id:"info-47"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://adguard.com/en/privacy.html"},"AdGuard Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-user"},"Nextcloud User"),(0,r.yg)("p",null,"Nextcloud is a ",(0,r.yg)("a",{parentName:"p",href:"https://nextcloud.com/install/#instructions-server"},"self hosted")," productivity platform, it can also be used free of charge with ",(0,r.yg)("a",{parentName:"p",href:"https://nextcloud.com/sign-up/"},"hundreds of existing hosting providers")," that offer a free Nextcloud account."),(0,r.yg)("p",null,"Displays branding information of a Nextcloud server (logo, url, slogan) and some user details (name, login name, last login, disk space or quota). Use with regular or admin user."),(0,r.yg)("p",null,"Shows quota usage when quota is enabled for the user or disk usage when not enabled."),(0,r.yg)("p",null,"Known issues: the User API incorrectly reports available disk space as total for admin users when quota is not enabled (which usually is the case for admins)."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/F8Fdm3t/nextcloud-user.png",alt:"nextcloud-user"})),(0,r.yg)("h4",{id:"options-49"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud username")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")))),(0,r.yg)("h4",{id:"example-46"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-user\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n")),(0,r.yg)("h4",{id:"info-48"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-user-statuses"},"Nextcloud User Statuses"),(0,r.yg)("p",null,"Show user statuses for selected users."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/Lk4DFT5/nextcloud-userstatus.png",alt:"nextcloud-userstatus"})),(0,r.yg)("h4",{id:"options-50"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud username")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"users"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud User IDs to show statuses for, list size between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"100"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showEmpty"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Show statuses without a message, defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"))))),(0,r.yg)("h4",{id:"example-47"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-userstatus\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n users: ['bob', 'alice']\n")),(0,r.yg)("h4",{id:"info-49"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-notifications"},"Nextcloud Notifications"),(0,r.yg)("p",null,"Displays your notifications and allows deleting them."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/yQCS51k/nextcloud-notifications.png",alt:"nextcloud-notifications"})),(0,r.yg)("h4",{id:"options-51"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud username")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number\\|string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit displayed notifications either by count, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"5")," to show the 5 most recent, or by age, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"1d")," to only show notifications not older than a day. Accepted suffixes for age limit are ",(0,r.yg)("inlineCode",{parentName:"td"},"m"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"h")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"d"),".")))),(0,r.yg)("h4",{id:"example-48"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-notifications\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n limit: 6h\n")),(0,r.yg)("h4",{id:"info-50"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-system"},"Nextcloud System"),(0,r.yg)("p",null,"Visualises overall memory utilisation and CPU load averages, shows server versions."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/KW4t6nG/nextcloud-system.png",alt:"nextcloud-system"})),(0,r.yg)("h4",{id:"options-52"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Must be a Nextcloud admin user")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")))),(0,r.yg)("h4",{id:"example-49"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-system\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n")),(0,r.yg)("h4",{id:"info-51"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-stats"},"Nextcloud Stats"),(0,r.yg)("p",null,"Shows key usage statistics about your Nextcloud server."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/pPXPQFB/nextcloud-stats.png",alt:"nextcloud-stats"})),(0,r.yg)("h4",{id:"options-53"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Must be a Nextcloud admin user")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")))),(0,r.yg)("h4",{id:"example-50"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-stats\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n")),(0,r.yg)("h4",{id:"info-52"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-php-opcache-stats"},"Nextcloud PHP OPcache Stats"),(0,r.yg)("p",null,"Shows statistics about PHP OPcache performance on your Nextcloud server."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/xf6M4J2/nextcloud-phpopcache.png",alt:"nextcloud-phpopcache"})),(0,r.yg)("h4",{id:"options-54"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Must be a Nextcloud admin user")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")))),(0,r.yg)("h4",{id:"example-51"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-php-opcache\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n")),(0,r.yg)("h4",{id:"info-53"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"proxmox-lists"},"Proxmox lists"),(0,r.yg)("p",null,"Shows lists of nodes, containers, and VMs in a Proxmox virtual environment cluster, with a status indicator."),(0,r.yg)("h4",{id:"options-55"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"cluster_url"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the proxmox cluster server. No trailing ",(0,r.yg)("inlineCode",{parentName:"td"},"/"),". for example: ",(0,r.yg)("inlineCode",{parentName:"td"},"https://proxmox.lan:8006"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"user_name"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A Proxmox API Username, for example ",(0,r.yg)("inlineCode",{parentName:"td"},"root@pam")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"dashy@pve"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"token_name"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A Proxmox API token name. You can get a token in the API section of the cluster management interface.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"token_uuid"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The value of the token entered above. This is normally a UUID.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"node"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"A Proxmox node name. If empty or not supplied, a list of nodes will be shown.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"node_data"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"This is required if a node is selected, Currently this accepts two values, either ",(0,r.yg)("inlineCode",{parentName:"td"},"lxc")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"qemu")," but the widget can be improved to get other types of data from the Proxmox API.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"A widget title.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title_as_link"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"When this is set to anything other than 0 or false, the title will be linked to the value entered in the ",(0,r.yg)("inlineCode",{parentName:"td"},"cluster_url")," option.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"footer"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"A widget footer.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"footer_as_link"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"When this is set to anything other than 0 or false, the title will be linked to the value entered in the ",(0,r.yg)("inlineCode",{parentName:"td"},"cluster_url")," option.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hide_templates"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"When this is set to anything other than 0 or false, templates will be filtered out of the result list.")))),(0,r.yg)("h4",{id:"example-52"},"Example"),(0,r.yg)("p",null,"This will show the list of nodes."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: proxmox-lists\n useProxy: true \n options:\n cluster_url: https://proxmox.lan:8006\n user_name: root@pam\n token_name: dashy\n token_uuid: bfb152df-abcd-abcd-abcd-ccb95a472d01\n")),(0,r.yg)("p",null,"This will show the list of VMs, with a title and a linked fotter, hiding VM templates."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: proxmox-lists\n useProxy: true \n options:\n cluster_url: https://proxmox.lan:8006\n user_name: root@pam\n token_name: dashy\n token_uuid: bfb152df-abcd-abcd-abcd-ccb95a472d01\n node: proxmox\n node_data: qemu\n title: Proxmox VMs\n title_as_link: false\n footer: Proxmox\n footer_as_link: true\n hide_templates: 1\n")),(0,r.yg)("h4",{id:"troubleshooting"},"Troubleshooting"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"404 Error in development mode"),": The error might disappear in production mode ",(0,r.yg)("inlineCode",{parentName:"li"},"yarn start")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"500 Error in production mode"),": Try adding the certificate authority (CA) certificate of your Proxmox host to Node.js. ",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Download the Proxmox CA certificate to your Dashy host."),(0,r.yg)("li",{parentName:"ul"},"Export environment variable ",(0,r.yg)("inlineCode",{parentName:"li"},"NODE_EXTRA_CA_CERTS")," and set its value to the path of the downloaded CA certificate. Example: ",(0,r.yg)("inlineCode",{parentName:"li"},"export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/devlab_ca.pem"))))),(0,r.yg)("h4",{id:"info-54"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://proxmox.com/en/proxmox-ve"},"Proxmox Virtual Environment"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://proxmox.com/en/privacy-policy"},"Proxmox's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"sabnzbd"},"Sabnzbd"),(0,r.yg)("p",null,"Shows queue information regarding your self hosted Sabnzbd server."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/5TTSRyM/sabnzbd.png",alt:"Sabnzbd"})),(0,r.yg)("h4",{id:"options-56"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sabnzbdUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Sabnzbd server. No trailing ",(0,r.yg)("inlineCode",{parentName:"td"},"/"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"API key for Sabnzbd access. Located under ",(0,r.yg)("inlineCode",{parentName:"td"},"Config")," -> ",(0,r.yg)("inlineCode",{parentName:"td"},"General")," -> ",(0,r.yg)("inlineCode",{parentName:"td"},"Security")," -> ",(0,r.yg)("inlineCode",{parentName:"td"},"API Key"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideDetails"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Hides extra server queue details.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideQueue"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Hides the queue list in an expandable dropdown.")))),(0,r.yg)("h4",{id:"example-53"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: sabnzbd\n options:\n sabnzbdUrl: 'https://sabnzbd.example.com'\n apiKey: XXXXXXXXXXXXXXXXXX\n hideDetails: false\n hideQueue: false\n")),(0,r.yg)("h4",{id:"info-55"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://sabnzbd.org/"},"Sabnzbd"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://forums.sabnzbd.org/ucp.php?mode=privacy"},"Sabnzbd Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"gluetun-vpn-info"},"Gluetun VPN Info"),(0,r.yg)("p",null,"Display info from the Gluetun VPN container public IP API. This can show the IP and location data for the exit VPN node."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/xjXbZ7Z/Screenshot-from-2022-07-20-21-42-34.png"})),(0,r.yg)("h4",{id:"options-57"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"visibleFields"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A comma separated list of the fields you want visible in the widget. You can have any number of the following : ",(0,r.yg)("inlineCode",{parentName:"td"},"public_ip"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"region"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"country"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"city"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"location"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"organisation"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"postal_code"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"timezone"),". Defaults to just ",(0,r.yg)("inlineCode",{parentName:"td"},"public_ip"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The url to the gluetun HTTP control server. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"http://gluetun:8000"))))),(0,r.yg)("h4",{id:"example-54"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gluetun-status\n useProxy: true\n options:\n hostname: http://server-or-conatiner-hostname:8000\n visibleFields: public_ip,region,country,city,location,organisation,postal_code,timezone\n")),(0,r.yg)("h4",{id:"info-56"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/qdm12/gluetun"},"Gluetun"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://github.com/qdm12/gluetun/wiki"},"Gluetun Wiki")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"drone-ci-builds"},"Drone CI Builds"),(0,r.yg)("p",null,"Display the last builds from a ",(0,r.yg)("a",{parentName:"p",href:"https://www.drone.ci"},"Drone CI")," instance. A self-hosted CI system that uses docker."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/nQM3BXj/Bildschirm-foto-2023-01-07-um-01-31-45.png"})),(0,r.yg)("h4",{id:"options-58"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The hostname of the Drone CI instance.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The API key (https://","[your-drone-instance]","/account).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"integer")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the amounts of listed builds.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"repo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Show only builds of the specified repo")))),(0,r.yg)("h4",{id:"example-55"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: drone-io\n updateInterval: 30\n options:\n host: https://drone.somedomain.com\n apiKey: my-very-secret-api-key\n limit: 10\n")),(0,r.yg)("h4",{id:"info-57"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://www.drone.io"},"Drone"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.drone.io"},"Drone")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"linkding"},"Linkding"),(0,r.yg)("p",null,"Linkding is a self-hosted bookmarking service, which has a clean interface and is simple to set up. This lists the links, filterable by tags."),(0,r.yg)("h4",{id:"options-59"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The hostname of the Drone CI instance.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The API key (https://your-linkding-instance/settings/integrations).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"tags"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"list of string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter the links by tag.")))),(0,r.yg)("h4",{id:"example-56"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: linkding\n updateInterval: 30\n options:\n host: https://lingding.somedomain.com\n apiKey: my-very-secret-api-key\n tags: \n - rpg\n - markdown\n")),(0,r.yg)("h4",{id:"info-58"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sissbruecker/linkding"},"Linkding"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://github.com/sissbruecker/linkding"},"Linkding")))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"system-resource-monitoring"},"System Resource Monitoring"),(0,r.yg)("h3",{id:"glances"},"Glances"),(0,r.yg)("p",null,"The easiest method for displaying system info and resource usage in Dashy is with ",(0,r.yg)("a",{parentName:"p",href:"https://nicolargo.github.io/glances/"},"Glances"),"."),(0,r.yg)("p",null,"Glances is a cross-platform monitoring tool developed by ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/nicolargo"},"@nicolargo"),". It's similar to top/htop but with a ",(0,r.yg)("a",{parentName:"p",href:"https://glances.readthedocs.io/en/latest/api.html"},"Rest API")," and many ",(0,r.yg)("a",{parentName:"p",href:"https://glances.readthedocs.io/en/latest/gw/index.html"},"data exporters")," available. Under the hood, it uses ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/giampaolo/psutil"},"psutil")," for retrieving system info."),(0,r.yg)("p",null,"If you don't already have it installed, either follow the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/nicolargo/glances/blob/master/README.rst"},"Installation Guide")," for your system, or setup ",(0,r.yg)("a",{parentName:"p",href:"https://glances.readthedocs.io/en/latest/docker.html"},"with Docker"),", or use the one-line install script: ",(0,r.yg)("inlineCode",{parentName:"p"},"curl -L https://bit.ly/glances | /bin/bash"),"."),(0,r.yg)("p",null,"If you are using Docker to run glances make sure to add the enviroment variable ",(0,r.yg)("inlineCode",{parentName:"p"},"-e TZ = {YourTimeZone}"),". You can get a list of valid timezones by running ",(0,r.yg)("inlineCode",{parentName:"p"},"timedatectl list-timezones")," on any linux system. This is needed so the graphs show the currect time."),(0,r.yg)("p",null,"Here an example for Docker"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," docker run -d \\\n --name glances \\\n --restart unless-stopped \\\n -v /var/run/docker.sock:/var/run/docker.sock:ro \\\n -p 61208:61208 \\\n --pid host \\\n --privileged \\\n -e GLANCES_OPT=-w \\\n -e PUID=1000 \\\n -e PGID=1000 \\\n -e TZ=Europe/Zurich \\\n nicolargo/glances:latest\n")),(0,r.yg)("p",null,"Glances can be launched with the ",(0,r.yg)("inlineCode",{parentName:"p"},"glances")," command. You'll need to run it in web server mode, using the ",(0,r.yg)("inlineCode",{parentName:"p"},"-w")," option for the API to be reachable. If you don't plan on using the Web UI, then you can disable it using ",(0,r.yg)("inlineCode",{parentName:"p"},"--disable-webui"),". See the ",(0,r.yg)("a",{parentName:"p",href:"https://glances.readthedocs.io/en/latest/cmds.html"},"command reference docs")," for more info."),(0,r.yg)("p",null,"If Glaces is running on a Windows system it is recommanded to add the following arguments ",(0,r.yg)("inlineCode",{parentName:"p"},"--disable-plugin all --enable-plugin cpu,mem,diskio,ip,network,containers,quicklook,load,fs,alert -w")," This is due to Glances not being that stable on windows, so disabling all plugins that aren't used by Dashy widgets can save on ressources."),(0,r.yg)("h4",{id:"options-60"},"Options"),(0,r.yg)("p",null,"All Glance's based widgets require a ",(0,r.yg)("inlineCode",{parentName:"p"},"hostname"),". All other parameters are optional."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL or IP + port to your Glances instance (without a trailing slash)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you have setup basic auth on Glances, specify username here (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"glances"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you have setup basic auth on Glances, specify password here. ",(0,r.yg)("strong",{parentName:"td"},"Note"),": since this password is in plaintext, it is important not to reuse it anywhere else")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiVersion"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify an API version, defaults to V ",(0,r.yg)("inlineCode",{parentName:"td"},"3"),". Note that support for older versions is limited")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"For widgets that show a time-series chart, optionally limit the number of data points returned. A higher number will show more historical results, but will take longer to load. A value between 300 - 800 is usually optimal")))),(0,r.yg)("p",null,"Note that if auth is configured, requests must be proxied with ",(0,r.yg)("inlineCode",{parentName:"p"},"useProxy: true")),(0,r.yg)("h4",{id:"info-59"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/nicolargo/glances"},"GitHub - Nicolargo/Glances"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("h4",{id:"screenshot"},"Screenshot"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://ibb.co/pR6dMZT"},(0,r.yg)("img",{parentName:"a",src:"https://i.ibb.co/xfK6BGb/system-monitor-board.png",alt:"example-screenshot"}))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"current-cpu-usage"},"Current CPU Usage"),(0,r.yg)("p",null,"Live-updating current CPU usage, as a combined average across all cores"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/qkLgxLp/gl-cpu-usage.png"})),(0,r.yg)("h4",{id:"example-57"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-current-cpu\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"current-cpu-usage-speedometer"},"Current CPU Usage Speedometer"),(0,r.yg)("p",null,"Speedometer styled version of the Current CPU Usage widget"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/7RHTRNq/gl-cpu-speedometer.png"})),(0,r.yg)("h4",{id:"example-58"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-cpu-speedometer\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cpu-usage-per-core"},"CPU Usage Per Core"),(0,r.yg)("p",null,"Live-updating CPU usage breakdown per core"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/512MYhT/gl-cpu-cores.png"})),(0,r.yg)("h4",{id:"example-59"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-current-cores\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cpu-usage-history"},"CPU Usage History"),(0,r.yg)("p",null,"Recent CPU usage history, across all cores, and displayed by user and system"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/zs8BDzR/gl-cpu-history.png"})),(0,r.yg)("h4",{id:"options-61"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of results returned, rendering more data points will take longer to load. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"100"))))),(0,r.yg)("h4",{id:"example-60"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-cpu-history\n options:\n hostname: http://192.168.130.2:61208\n limit: 60\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"current-memory-usage"},"Current Memory Usage"),(0,r.yg)("p",null,"Real-time memory usage gauge, with more info visible on click"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/rynp52J/gl-mem-usage.png"})),(0,r.yg)("h4",{id:"example-61"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-current-mem\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"current-memory-usage-speedometer"},"Current Memory Usage Speedometer"),(0,r.yg)("p",null,"Speedometer styled version of the Current Memory Usage widget"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/wsNW7Xr/gl-mem-speedometer.png"})),(0,r.yg)("h4",{id:"example-62"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-mem-speedometer\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"memory-usage-history"},"Memory Usage History"),(0,r.yg)("p",null,"Recent memory usage chart"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/V3wSgW0/gl-mem-history.png"})),(0,r.yg)("h4",{id:"options-62"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of results returned, rendering more data points will take longer to load. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"100"))))),(0,r.yg)("h4",{id:"example-63"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-mem-history\n options:\n hostname: http://localhost:61208\n limit: 80\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"disk-space"},"Disk Space"),(0,r.yg)("p",null,"List connected disks, showing free / used space and other info (file system, mount point and space available)"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/25y94bB/gl-disk-usage.png"})),(0,r.yg)("h4",{id:"example-64"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-disk-space\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"disk-io"},"Disk IO"),(0,r.yg)("p",null,"Shows real-time read and write speeds and operations per sec for each disk"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/JdgjCjG/gl-disk-io.png"})),(0,r.yg)("h4",{id:"example-65"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-disk-io\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"system-load"},"System Load"),(0,r.yg)("p",null,"Shows the number of processes waiting in the run-queue, averaged across all cores. Displays for past 5, 10 and 15 minutes"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/090FfNy/gl-system-load.png"})),(0,r.yg)("h4",{id:"example-66"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-system-load\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"system-load-history"},"System Load History"),(0,r.yg)("p",null,"Shows recent historical system load, calculated from the number of processes waiting in the run-queue, in 1, 5 and 15 minute intervals, and averaged across all cores. Optionally specify ",(0,r.yg)("inlineCode",{parentName:"p"},"limit")," to set number of results returned, defaults to ",(0,r.yg)("inlineCode",{parentName:"p"},"500"),", max ",(0,r.yg)("inlineCode",{parentName:"p"},"100000"),", but the higher the number the longer the load and render times will be."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/C2rGMLg/system-load-history.png"})),(0,r.yg)("h4",{id:"example-67"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-load-history\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"network-interfaces"},"Network Interfaces"),(0,r.yg)("p",null,"Lists visible network interfaces, including real-time upload/ download stats"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/FnhgHfG/gl-network-interfaces.png"})),(0,r.yg)("h4",{id:"example-68"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-network-interfaces\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"network-traffic"},"Network Traffic"),(0,r.yg)("p",null,"Shows amount of data recently uploaded/ downloaded across all network interfaces. Optionally set the ",(0,r.yg)("inlineCode",{parentName:"p"},"limit")," option to specify number historical of data points to return"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/12RN6KT/gl-network-traffic.png"})),(0,r.yg)("h4",{id:"example-69"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-network-traffic\n options:\n hostname: http://192.168.130.2:61208\n limit: 500\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"resource-usage-alerts"},"Resource Usage Alerts"),(0,r.yg)("p",null,"Lists recent high resource usage alerts (e.g. CPU, mem, IO, load, temp)"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/w01NX5R/gl-alerts.png"})),(0,r.yg)("h4",{id:"example-70"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-alerts\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"ip-address"},"IP Address"),(0,r.yg)("p",null,"Shows public and private IP address. Note that the ip plugin is not available on all instances of Glances."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/ZhXBxZr/gl-ip-address.png"})),(0,r.yg)("h4",{id:"example-71"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-ip-address\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cpu-temp"},"CPU Temp"),(0,r.yg)("p",null,"Displays temperature data from system CPUs."),(0,r.yg)("p",null,"Note: This widget uses the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/nicolargo/glances/blob/develop/glances/plugins/glances_sensors.py"},(0,r.yg)("inlineCode",{parentName:"a"},"sensors"))," plugin, which is disabled by default, and may cause ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/nicolargo/glances/issues/1664#issuecomment-632063558"},"performance issues"),".\nYou'll need to enable the sensors plugin to use this widget, using: ",(0,r.yg)("inlineCode",{parentName:"p"},"--enable-plugin sensors")," when you start Glances."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/xSs4Gqd/gl-cpu-temp.png"})),(0,r.yg)("h4",{id:"options-63"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"units"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Use ",(0,r.yg)("inlineCode",{parentName:"td"},"C")," to display temperatures in Celsius or ",(0,r.yg)("inlineCode",{parentName:"td"},"F")," to use Fahrenheit. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"C"),".")))),(0,r.yg)("h4",{id:"example-72"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-cpu-temp\n options:\n hostname: http://192.168.130.2:61208\n units: C\n")),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"dynamic-widgets"},"Dynamic Widgets"),(0,r.yg)("h3",{id:"iframe-widget"},"Iframe Widget"),(0,r.yg)("p",null,"Embed any webpage into your dashboard as a widget."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/t4VHnh3/iframe-widget.gif"})),(0,r.yg)("h4",{id:"options-64"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"url"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to the webpage to embed")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"frameHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If needed, specify height of iframe in ",(0,r.yg)("inlineCode",{parentName:"td"},"px"),". E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"400"),", defaults to auto")))),(0,r.yg)("h4",{id:"example-73"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: iframe\n options:\n url: https://fiatleak.com/\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"html-embedded-widget"},"HTML Embedded Widget"),(0,r.yg)("p",null,"Many websites and apps provide their own embeddable widgets. These can be used with Dashy using the Embed widget, which lets you dynamically embed and HTML, CSS or JavaScript contents."),(0,r.yg)("p",null,"\u26a0\ufe0f ",(0,r.yg)("strong",{parentName:"p"},"NOTE:")," Use with extreme caution. Embedding a script from an untrustworthy source may have serious unintended consequences."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/fkwNnxT/embed-widget-2.png"})),(0,r.yg)("h4",{id:"options-65"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"html"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"HTML contents to render in the widget")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"script"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Raw JavaScript code to execute (caution)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"scriptSrc"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A URL to JavaScript content (caution)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"css"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Any stylings for widget contents")))),(0,r.yg)("h4",{id:"example-74"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},'- type: embed\n options:\n scriptSrc: https://cdn.speedcheck.org/basic/scbjs.min.js\n html: |\n
\n
\n \n Speedcheck\n \n
\n
\n')),(0,r.yg)("p",null,"Or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},'- type: embed\n options:\n css: \'.coinmarketcap-currency-widget { color: var(--widget-text-color); }\'\n html: \'
\'\n scriptSrc: \'https://files.coinmarketcap.com/static/widget/currency.js\'\n')),(0,r.yg)("p",null,"You can also use this widget to display an image, wither locally or from a remote origin."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: embed\n options:\n html: ''\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"api-response"},"API Response"),(0,r.yg)("p",null,"Directly output plain-text response from any API-enabled service."),(0,r.yg)("p",null,"// Coming soon..."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"prometheus-data"},"Prometheus Data"),(0,r.yg)("p",null,"Display data from any service with a Prometheus exporter."),(0,r.yg)("p",null,"// Coming soon..."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"data-feed"},"Data Feed"),(0,r.yg)("p",null,"Show live data from an RSS-enabled service. The only required parameter is ",(0,r.yg)("inlineCode",{parentName:"p"},"rssUrl"),", which is the URL to the ATOM feed. See ",(0,r.yg)("a",{parentName:"p",href:"#rss-feed"},"RSS Widget")," for full list of available options."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"700",src:"https://i.ibb.co/1r88pvL/rss-feed-example-1.png"})),(0,r.yg)("h4",{id:"example-75"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: rss-feed\n options:\n rssUrl: https://notes.aliciasykes.com/feed\n")),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"usage--customizations"},"Usage & Customizations"),(0,r.yg)("h3",{id:"widget-usage-guide"},"Widget Usage Guide"),(0,r.yg)("p",null,"Like items, widgets are placed under sections. You may have one or more widgets per section."),(0,r.yg)("p",null,"In your YAML config file, this will look something like:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"sections:\n- name: Today\n icon: far fa-calendar-day\n widgets:\n - type: clock\n options:\n format: en-GB\n - type: weather\n options:\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n city: London\n units: metric\n")),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},'In this example, there is a single section, named "Today", using a Calendar icon from Font-Awesome. It has 2 widgets, a clock and the current weather.')),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"continuous-updates"},"Continuous Updates"),(0,r.yg)("p",null,"By default, a widget which displays dynamic data from an external source, will only fetch results on page load. If you would like to keep data updated at all times, you can enable ",(0,r.yg)("strong",{parentName:"p"},"Continuous Updates"),". This is done by setting a time value in the ",(0,r.yg)("inlineCode",{parentName:"p"},"updateInterval")," field."),(0,r.yg)("p",null,"The value of ",(0,r.yg)("inlineCode",{parentName:"p"},"updateInterval")," is optional, and is specified and seconds. It must be more than ",(0,r.yg)("inlineCode",{parentName:"p"},"10")," and less than ",(0,r.yg)("inlineCode",{parentName:"p"},"7200"),"."),(0,r.yg)("p",null,"For example, the following widget displaying stats from Pi-Hole will update ever 20 seconds."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"widgets:\n- type: pi-hole-stats\n updateInterval: 20\n options:\n hostname: http://192.168.130.2\n")),(0,r.yg)("p",null,"Note that if you have many widgets, and set them to continuously update frequently, you will notice a hit to performance. A widget that relies on data from an external API, will also consume your usage quota faster, if set to keep updating."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"proxying-requests"},"Proxying Requests"),(0,r.yg)("p",null,"If a widget fails to make a data request, and the console shows a CORS error, this means the server is blocking client-side requests."),(0,r.yg)("p",null,"Dashy has a built-in CORS proxy (",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/services/cors-proxy.js"},(0,r.yg)("inlineCode",{parentName:"a"},"services/cors-proxy.js")),"), which will be used automatically by some widgets, or can be forced to use by other by setting the ",(0,r.yg)("inlineCode",{parentName:"p"},"useProxy")," option."),(0,r.yg)("p",null,"For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"widgets:\n- type: pi-hole-stats\n useProxy: true\n options:\n hostname: http://pi-hole.local\n")),(0,r.yg)("p",null,"Alternatively, and more securely, you can set the auth headers on your service to accept requests from Dashy. For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"Access-Control-Allow-Origin: https://location-of-dashy/\nVary: Origin\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"setting-timeout"},"Setting Timeout"),(0,r.yg)("p",null,"If the endpoint you are requesting data from is slow to respond, you may see a timeout error in the console. This can easily be fixed by specifying the ",(0,r.yg)("inlineCode",{parentName:"p"},"timeout")," property on the offending widget. This should be an integer value, in milliseconds. By default timeout is ",(0,r.yg)("inlineCode",{parentName:"p"},"2500")," ms (2\xbd seconds)."),(0,r.yg)("p",null,"For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-current-cpu\n timeout: 8000\n options:\n hostname: https://glances.dns-device.local\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adding-labels"},"Adding Labels"),(0,r.yg)("p",null,"If you have multiple widgets of the same type in a single section, it may not be clear what each one is. To overcome this, you can add a custom label to any given widget, using the ",(0,r.yg)("inlineCode",{parentName:"p"},"label")," property."),(0,r.yg)("p",null,"For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- name: CPU Usage\n icon: fas fa-tachometer\n widgets:\n - type: gl-current-cpu\n label: Meida Server\n options:\n hostname: http://media-server.lan:61208\n - type: gl-current-cpu\n label: Firewall\n options:\n hostname: http://firewall.lan:61208\n - type: gl-current-cpu\n label: File Sync Server\n options:\n hostname: http://file-sync.lan:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"ignoring-errors"},"Ignoring Errors"),(0,r.yg)("p",null,"When there's an error fetching or displaying a widgets data, then it will be highlighted in yellow, and a message displayed on the UI."),(0,r.yg)("p",null,"In some instances, this is a false positive, and the widget is actually functioning correctly. If this is the case, you can disable the UI error message of a given widget by setting: ",(0,r.yg)("inlineCode",{parentName:"p"},"ignoreErrors: true")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-disk-io\n ignoreErrors: true\n options:\n hostname: https://glances.dns-device.local\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"widget-styling"},"Widget Styling"),(0,r.yg)("p",null,"Like elsewhere in Dashy, all colours can be easily modified with CSS variables."),(0,r.yg)("p",null,"Widgets use the following color variables, which can be overridden if desired:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"--widget-text-color")," - Text color, defaults to ",(0,r.yg)("inlineCode",{parentName:"li"},"--primary")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"--widget-background-color")," - Background color, defaults to ",(0,r.yg)("inlineCode",{parentName:"li"},"--background-darker")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"--widget-accent-color")," - Accent color, defaults to ",(0,r.yg)("inlineCode",{parentName:"li"},"--background"))),(0,r.yg)("p",null,"For more info on how to apply custom variables, see the ",(0,r.yg)("a",{parentName:"p",href:"/docs/theming#setting-custom-css-in-the-ui"},"Theming Docs")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"customizing-charts"},"Customizing Charts"),(0,r.yg)("p",null,"For widgets that contain charts, you can set an array of colors under ",(0,r.yg)("inlineCode",{parentName:"p"},"chartColors"),".\nTo specify the chart height, set ",(0,r.yg)("inlineCode",{parentName:"p"},"chartHeight")," to an integer (in ",(0,r.yg)("inlineCode",{parentName:"p"},"px"),"), defaults to ",(0,r.yg)("inlineCode",{parentName:"p"},"300"),".\nFor example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-load-history\n options:\n hostname: http://192.168.130.2:61208\n chartColors: ['#9b5de5', '#f15bb5', '#00bbf9', '#00f5d4']\n chartHeight: 450\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"language-translations"},"Language Translations"),(0,r.yg)("p",null,"Since most of the content displayed within widgets is fetched from an external API, unless that API supports multiple languages, translating dynamic content is not possible."),(0,r.yg)("p",null,"However, any hard-coded content is translatable, and all dates and times will display in your local format."),(0,r.yg)("p",null,"For more info about multi-language support, see the ",(0,r.yg)("a",{parentName:"p",href:"/docs/multi-language-support"},"Internationalization Docs"),"."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"widget-ui-options"},"Widget UI Options"),(0,r.yg)("p",null,"Widgets can be opened in full-page view, by clicking the Arrow icon (top-right). The URL in your address bar will also update, and visiting that web address directly will take you straight to that widget."),(0,r.yg)("p",null,"You can reload the data of any widget, by clicking the Refresh Data icon (also in top-right). This will only affect the widget where the action was triggered from."),(0,r.yg)("p",null,"All ",(0,r.yg)("a",{parentName:"p",href:"/docs/configuring#section"},"config options")," that can be applied to sections, can also be applied to widget sections. For example, to make a widget section double the width, set ",(0,r.yg)("inlineCode",{parentName:"p"},"displayData.cols: 2")," within the parent section. You can collapse a widget (by clicking the section title), and collapse state will be saved locally."),(0,r.yg)("p",null,"Widgets cannot currently be edited through the UI. This feature is in development, and will be released soon. In the meantime, you can either use the JSON config editor, or use ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/coder/code-server"},"VS Code Server"),", or just SSH into your box and edit the conf.yml file directly."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"build-your-own-widget"},"Build your own Widget"),(0,r.yg)("p",null,"Widgets are built in a modular fashion, making it easy for anyone to create their own custom components."),(0,r.yg)("p",null,"For a full tutorial on creating your own widget, you can follow ",(0,r.yg)("a",{parentName:"p",href:"/docs/development-guides/#building-a-widget"},"this guide"),", or take a look at ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/commit/3da76ce2999f57f76a97454c0276301e39957b8e"},"here")," for a code example."),(0,r.yg)("p",null,"Alternatively, for displaying simple data, you could also just use the either the ",(0,r.yg)("a",{parentName:"p",href:"#iframe-widget"},"iframe"),", ",(0,r.yg)("a",{parentName:"p",href:"#html-embedded-widget"},"embed"),", ",(0,r.yg)("a",{parentName:"p",href:"#data-feed"},"data feed")," or ",(0,r.yg)("a",{parentName:"p",href:"#api-response"},"API response")," widgets."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"requesting-a-widget"},"Requesting a Widget"),(0,r.yg)("p",null,"Suggestions for widget ideas are welcome. But there is no guarantee that I will build your widget idea."),(0,r.yg)("p",null,"Please only request widgets for services that:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Have a publicly accessible API"),(0,r.yg)("li",{parentName:"ul"},"Are CORS and HTTPS enabled"),(0,r.yg)("li",{parentName:"ul"},"Are free to use, or have a free plan"),(0,r.yg)("li",{parentName:"ul"},"Allow for use in their Terms of Service"),(0,r.yg)("li",{parentName:"ul"},"Would be useful for other users")),(0,r.yg)("p",null,"You can suggest a widget ",(0,r.yg)("a",{parentName:"p",href:"https://git.io/Jygo3"},"here"),", please star the repo before submitting a ticket. If you are a monthly GitHub sponsor, I will happily build out a custom widget for any service that meets the above criteria, usually within 2 weeks of initial request."),(0,r.yg)("p",null,"For services that are not officially supported, it is likely still possible to display data using either the ",(0,r.yg)("a",{parentName:"p",href:"#iframe-widget"},"iframe"),", ",(0,r.yg)("a",{parentName:"p",href:"#html-embedded-widget"},"embed")," or ",(0,r.yg)("a",{parentName:"p",href:"#api-response"},"API response")," widgets. For more advanced features, like charts and action buttons, you could also build your own widget, using ",(0,r.yg)("a",{parentName:"p",href:"/docs/development-guides/#building-a-widget"},"this tutorial"),", it's fairly straight forward, and you can use an ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/tree/master/src/components/Widgets"},"existing widget")," (or ",(0,r.yg)("a",{parentName:"p",href:"https://git.io/JygKI"},"this example"),") as a template."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"troubleshooting-widget-errors"},"Troubleshooting Widget Errors"),(0,r.yg)("p",null,"If an error occurs when fetching or rendering results, you will see a short message in the UI. If that message doesn't adequately explain the problem, then you can ",(0,r.yg)("a",{parentName:"p",href:"/docs/troubleshooting#how-to-open-browser-console"},"open the browser console")," to see more details."),(0,r.yg)("p",null,"Before proceeding, ensure that if the widget requires auth your API is correct, and for custom widgets, double check that the URL and protocol is correct."),(0,r.yg)("p",null,"If you're able to, you can find more information about why the request may be failing in the Dev Tools under the Network tab, and you can ensure your endpoint is correct and working using a tool like Postman."),(0,r.yg)("h4",{id:"cors-errors"},"CORS Errors"),(0,r.yg)("p",null,"The most common issue is a CORS error. This is a browser security mechanism which prevents the client-side app (Dashy) from from accessing resources on a remote origin, without that server's explicit permission (e.g. with headers like Access-Control-Allow-Origin). See the MDN Docs for more info: ",(0,r.yg)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"Cross-Origin Resource Sharing"),"."),(0,r.yg)("p",null,"There are several ways to fix a CORS error:"),(0,r.yg)("h4",{id:"option-1---ensure-correct-protocol"},"Option 1 - Ensure Correct Protocol"),(0,r.yg)("p",null,"You will get a CORS error if you try and access a http service from a https source. So ensure that the URL you are requesting has the right protocol, and is correctly formatted."),(0,r.yg)("h4",{id:"option-2---set-headers"},"Option 2 - Set Headers"),(0,r.yg)("p",null,"If you have control over the destination (e.g. for a self-hosted service), then you can simply apply the correct headers.\nAdd the ",(0,r.yg)("inlineCode",{parentName:"p"},"Access-Control-Allow-Origin")," header, with the value of either ",(0,r.yg)("inlineCode",{parentName:"p"},"*")," to allow requests from anywhere, or more securely, the host of where Dashy is served from. For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"Access-Control-Allow-Origin: https://url-of-dashy.local\n")),(0,r.yg)("p",null,"or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"Access-Control-Allow-Origin: *\n")),(0,r.yg)("h4",{id:"option-3---proxying-request"},"Option 3 - Proxying Request"),(0,r.yg)("p",null,"You can route requests through Dashy's built-in CORS proxy. Instructions and more details can be found ",(0,r.yg)("a",{parentName:"p",href:"#proxying-requests"},"here"),". If you don't have control over the target origin, and you are running Dashy either through Docker, with the Node server or on Netlify, then this solution will work for you."),(0,r.yg)("p",null,"Just add the ",(0,r.yg)("inlineCode",{parentName:"p"},"useProxy: true")," option to the failing widget."),(0,r.yg)("h4",{id:"option-4---use-a-plugin"},"Option 4 - Use a plugin"),(0,r.yg)("p",null,"For testing purposes, you can use an addon, which will disable the CORS checks. You can get the Allow-CORS extension for ",(0,r.yg)("a",{parentName:"p",href:"https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?hl=en-US"},"Chrome")," or ",(0,r.yg)("a",{parentName:"p",href:"https://addons.mozilla.org/en-US/firefox/addon/access-control-allow-origin/"},"Firefox"),", more details ",(0,r.yg)("a",{parentName:"p",href:"https://mybrowseraddon.com/access-control-allow-origin.html"},"here")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"raising-an-issue"},"Raising an Issue"),(0,r.yg)("p",null,"If you need to submit a bug report for a failing widget, then please include the full console output (see ",(0,r.yg)("a",{parentName:"p",href:"/docs/troubleshooting#how-to-open-browser-console"},"how"),") as well as the relevant parts of your config file. Before sending the request, ensure you've read the docs. If you're new to GitHub, an haven't previously contributed to the project, then please fist star the repo to avoid your ticket being closed by the anti-spam bot."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9be9f402.e10e35ea.js b/assets/js/9be9f402.e10e35ea.js new file mode 100644 index 00000000..d6d2117c --- /dev/null +++ b/assets/js/9be9f402.e10e35ea.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdashy=self.webpackChunkdashy||[]).push([[552],{5680:(e,t,a)=>{a.d(t,{xA:()=>y,yg:()=>u});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=n.createContext({}),p=function(e){var t=n.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},y=function(e){var t=p(e.components);return n.createElement(o.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},s=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,y=g(e,["components","mdxType","originalType","parentName"]),d=p(a),s=r,u=d["".concat(o,".").concat(s)]||d[s]||m[s]||l;return a?n.createElement(u,i(i({ref:t},y),{},{components:a})):n.createElement(u,i({ref:t},y))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,i=new Array(l);i[0]=s;var g={};for(var o in t)hasOwnProperty.call(t,o)&&(g[o]=t[o]);g.originalType=e,g[d]="string"==typeof e?e:r,i[1]=g;for(var p=2;p{a.r(t),a.d(t,{contentTitle:()=>i,default:()=>d,frontMatter:()=>l,metadata:()=>g,toc:()=>o});var n=a(8168),r=(a(6540),a(5680));const l={},i="Widgets",g={unversionedId:"widgets",id:"widgets",isDocsHomePage:!1,title:"Widgets",description:"Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API.",source:"@site/docs/widgets.md",sourceDirName:".",slug:"/widgets",permalink:"/docs/widgets",editUrl:"https://github.com/Lissy93/dashy/edit/gh-pages/docs/docs/widgets.md",version:"current",frontMatter:{},sidebar:"dashySidebar",previous:{title:"Icons",permalink:"/docs/icons"},next:{title:"Theming",permalink:"/docs/theming"}},o=[{value:"Contents",id:"contents",children:[]},{value:"General Widgets",id:"general-widgets",children:[{value:"Clock",id:"clock",children:[]},{value:"Weather",id:"weather",children:[]},{value:"Weather Forecast",id:"weather-forecast",children:[]},{value:"RSS Feed",id:"rss-feed",children:[]},{value:"Image",id:"image",children:[]},{value:"Public IP",id:"public-ip",children:[]},{value:"IP Blacklist",id:"ip-blacklist",children:[]},{value:"Domain Monitor",id:"domain-monitor",children:[]},{value:"Crypto Watch List",id:"crypto-watch-list",children:[]},{value:"Crypto Token Price History",id:"crypto-token-price-history",children:[]},{value:"Wallet Balance",id:"wallet-balance",children:[]},{value:"Code Stats",id:"code-stats",children:[]},{value:"Mullvad Status",id:"mullvad-status",children:[]},{value:"AnonAddy",id:"anonaddy",children:[]},{value:"Vulnerability Feed",id:"vulnerability-feed",children:[]},{value:"Exchange Rates",id:"exchange-rates",children:[]},{value:"Public Holidays",id:"public-holidays",children:[]},{value:"Covid-19 Status",id:"covid-19-status",children:[]},{value:"Sports Scores",id:"sports-scores",children:[]},{value:"News Headlines",id:"news-headlines",children:[]},{value:"TFL Status",id:"tfl-status",children:[]},{value:"Stock Price History",id:"stock-price-history",children:[]},{value:"ETH Gas Prices",id:"eth-gas-prices",children:[]},{value:"Joke",id:"joke",children:[]},{value:"XKCD Comics",id:"xkcd-comics",children:[]},{value:"Flight Data",id:"flight-data",children:[]},{value:"Astronomy Picture of the Day",id:"astronomy-picture-of-the-day",children:[]},{value:"GitHub Trending",id:"github-trending",children:[]},{value:"GitHub Profile Stats",id:"github-profile-stats",children:[]},{value:"HealthChecks Status",id:"healthchecks-status",children:[]},{value:"Hackernews Trending",id:"hackernews-trending",children:[]},{value:"MVG Departure",id:"mvg-departure",children:[]},{value:"MVG Connection",id:"mvg-connection",children:[]},{value:"Custom search",id:"custom-search",children:[]},{value:"RescueTime Overview",id:"rescuetime-overview",children:[]}]},{value:"Self-Hosted Services Widgets",id:"self-hosted-services-widgets",children:[{value:"System Info",id:"system-info",children:[]},{value:"Cron Monitoring (Health Checks)",id:"cron-monitoring-health-checks",children:[]},{value:"CPU History (NetData)",id:"cpu-history-netdata",children:[]},{value:"Memory History (NetData)",id:"memory-history-netdata",children:[]},{value:"Load History (NetData)",id:"load-history-netdata",children:[]},{value:"Pi Hole Stats",id:"pi-hole-stats",children:[]},{value:"Pi Hole Queries",id:"pi-hole-queries",children:[]},{value:"Pi Hole Recent Traffic",id:"pi-hole-recent-traffic",children:[]},{value:"Stat Ping Statuses",id:"stat-ping-statuses",children:[]},{value:"Synology Download Station",id:"synology-download-station",children:[]},{value:"AdGuard Home Block Stats",id:"adguard-home-block-stats",children:[]},{value:"AdGuard Home Filters",id:"adguard-home-filters",children:[]},{value:"AdGuard Home DNS Info",id:"adguard-home-dns-info",children:[]},{value:"AdGuard Home Top Domains",id:"adguard-home-top-domains",children:[]},{value:"Nextcloud User",id:"nextcloud-user",children:[]},{value:"Nextcloud User Statuses",id:"nextcloud-user-statuses",children:[]},{value:"Nextcloud Notifications",id:"nextcloud-notifications",children:[]},{value:"Nextcloud System",id:"nextcloud-system",children:[]},{value:"Nextcloud Stats",id:"nextcloud-stats",children:[]},{value:"Nextcloud PHP OPcache Stats",id:"nextcloud-php-opcache-stats",children:[]},{value:"Proxmox lists",id:"proxmox-lists",children:[]},{value:"Sabnzbd",id:"sabnzbd",children:[]},{value:"Gluetun VPN Info",id:"gluetun-vpn-info",children:[]},{value:"Drone CI Builds",id:"drone-ci-builds",children:[]},{value:"Linkding",id:"linkding",children:[]},{value:"Uptime Kuma",id:"uptime-kuma",children:[]}]},{value:"System Resource Monitoring",id:"system-resource-monitoring",children:[{value:"Glances",id:"glances",children:[]},{value:"Current CPU Usage",id:"current-cpu-usage",children:[]},{value:"Current CPU Usage Speedometer",id:"current-cpu-usage-speedometer",children:[]},{value:"CPU Usage Per Core",id:"cpu-usage-per-core",children:[]},{value:"CPU Usage History",id:"cpu-usage-history",children:[]},{value:"Current Memory Usage",id:"current-memory-usage",children:[]},{value:"Current Memory Usage Speedometer",id:"current-memory-usage-speedometer",children:[]},{value:"Memory Usage History",id:"memory-usage-history",children:[]},{value:"Disk Space",id:"disk-space",children:[]},{value:"Disk IO",id:"disk-io",children:[]},{value:"System Load",id:"system-load",children:[]},{value:"System Load History",id:"system-load-history",children:[]},{value:"Network Interfaces",id:"network-interfaces",children:[]},{value:"Network Traffic",id:"network-traffic",children:[]},{value:"Resource Usage Alerts",id:"resource-usage-alerts",children:[]},{value:"IP Address",id:"ip-address",children:[]},{value:"CPU Temp",id:"cpu-temp",children:[]}]},{value:"Dynamic Widgets",id:"dynamic-widgets",children:[{value:"Iframe Widget",id:"iframe-widget",children:[]},{value:"HTML Embedded Widget",id:"html-embedded-widget",children:[]},{value:"API Response",id:"api-response",children:[]},{value:"Prometheus Data",id:"prometheus-data",children:[]},{value:"Data Feed",id:"data-feed",children:[]}]},{value:"Usage & Customizations",id:"usage--customizations",children:[{value:"Widget Usage Guide",id:"widget-usage-guide",children:[]},{value:"Continuous Updates",id:"continuous-updates",children:[]},{value:"Proxying Requests",id:"proxying-requests",children:[]},{value:"Setting Timeout",id:"setting-timeout",children:[]},{value:"Adding Labels",id:"adding-labels",children:[]},{value:"Ignoring Errors",id:"ignoring-errors",children:[]},{value:"Widget Styling",id:"widget-styling",children:[]},{value:"Customizing Charts",id:"customizing-charts",children:[]},{value:"Language Translations",id:"language-translations",children:[]},{value:"Widget UI Options",id:"widget-ui-options",children:[]},{value:"Build your own Widget",id:"build-your-own-widget",children:[]},{value:"Requesting a Widget",id:"requesting-a-widget",children:[]},{value:"Troubleshooting Widget Errors",id:"troubleshooting-widget-errors",children:[]},{value:"Raising an Issue",id:"raising-an-issue",children:[]}]}],p={toc:o},y="wrapper";function d(e){let{components:t,...a}=e;return(0,r.yg)(y,(0,n.A)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"widgets"},"Widgets"),(0,r.yg)("p",null,"Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API."),(0,r.yg)("h2",{id:"contents"},"Contents"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#general-widgets"},"General Widgets")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#clock"},"Clock")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#weather"},"Weather")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#weather-forecast"},"Weather Forecast")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#rss-feed"},"RSS Feed")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#image"},"Image")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#public-ip"},"Public IP Address")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#ip-blacklist"},"IP Blacklist Checker")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#domain-monitor"},"Domain Monitor")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#crypto-watch-list"},"Crypto Watch List")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#crypto-token-price-history"},"Crypto Price History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#wallet-balance"},"Crypto Wallet Balance")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#code-stats"},"Code Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#mullvad-status"},"Mullvad Status")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#anonaddy"},"Email Aliases (AnonAddy)")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#vulnerability-feed"},"Vulnerability Feed")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#exchange-rates"},"Exchange Rates")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#public-holidays"},"Public Holidays")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#covid-19-status"},"Covid-19 Status")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sports-scores"},"Sports Scores")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#news-headlines"},"News Headlines")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#tfl-status"},"TFL Status")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#stock-price-history"},"Stock Price History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#eth-gas-prices"},"ETH Gas Prices")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#joke"},"Joke of the Day")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#xkcd-comics"},"XKCD Comics")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#flight-data"},"Flight Data")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#astronomy-picture-of-the-day"},"NASA APOD")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#github-trending"},"GitHub Trending")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#github-profile-stats"},"GitHub Profile Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#healthchecks-status"},"Healthchecks Status")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#hackernews-trending"},"Hackernews Trending")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#mvg-departure"},"Mvg Departure")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#mvg-connection"},"Mvg Connection")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#custom-search"},"Custom search")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#rescuetime-overview"},"Rescuetime overview")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#self-hosted-services-widgets"},"Self-Hosted Services Widgets")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#system-info"},"System Info")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cron-monitoring-health-checks"},"Cron Monitoring")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpu-history-netdata"},"CPU History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#memory-history-netdata"},"Memory History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#load-history-netdata"},"System Load History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pi-hole-stats"},"Pi Hole Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pi-hole-queries"},"Pi Hole Queries")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#pi-hole-recent-traffic"},"Pi Hole Recent Traffic")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#stat-ping-statuses"},"Stat Ping Statuses")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#synology-download-station"},"Synology Download Station")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adguard-home-block-stats"},"AdGuard Home Block Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adguard-home-filters"},"AdGuard Home Filters")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adguard-home-dns-info"},"AdGuard Home DNS Info")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adguard-home-top-domains"},"AdGuard Home Top Domains")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-user"},"Nextcloud User")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-user-statuses"},"Nextcloud User Statuses")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-notifications"},"Nextcloud Notifications")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-system"},"Nextcloud System")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-stats"},"Nextcloud Stats")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#nextcloud-php-opcache-stats"},"Nextcloud PHP OPcache")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#proxmox-lists"},"Proxmox lists")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#sabnzbd"},"Sabnzbd")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#gluetun-vpn-info"},"Gluetun VPN Info")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#drone-ci-builds"},"Drone CI Build")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#linkding"},"Linkding")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#uptime-kuma"},"Uptime Kuma")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#system-resource-monitoring"},"System Resource Monitoring")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#current-cpu-usage"},"CPU Usage Current")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpu-usage-per-core"},"CPU Usage Per Core")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpu-usage-history"},"CPU Usage History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#current-memory-usage"},"Memory Usage Current")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#memory-usage-history"},"Memory Usage History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#disk-space"},"Disk Space")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#disk-io"},"Disk IO")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#system-load"},"System Load")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#system-load-history"},"System Load History")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#network-interfaces"},"Network Interfaces")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#network-traffic"},"Network Traffic")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#resource-usage-alerts"},"Resource Usage Alerts")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#ip-address"},"Public & Private IP")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#cpu-temp"},"CPU Temperature")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#dynamic-widgets"},"Dynamic Widgets")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#iframe-widget"},"Iframe Widget")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#html-embedded-widget"},"HTML Embed Widget")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#api-response"},"API Response")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#prometheus-data"},"Prometheus Data")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#data-feed"},"Data Feed")))),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},(0,r.yg)("a",{parentName:"strong",href:"#usage--customizations"},"Usage & Customizations")),(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#widget-usage-guide"},"Widget Usage Guide")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#continuous-updates"},"Continuous Updates")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#proxying-requests"},"Proxying Requests")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#setting-timeout"},"Setting Timeout")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#adding-labels"},"Adding Labels")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#ignoring-errors"},"Ignoring Errors")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#widget-styling"},"Custom CSS Styling")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#customizing-charts"},"Customizing Charts")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#language-translations"},"Language Translations")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#widget-ui-options"},"Widget UI Options")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#build-your-own-widget"},"Building a Widget")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#requesting-a-widget"},"Requesting a Widget")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"#troubleshooting-widget-errors"},"Troubleshooting"))))),(0,r.yg)("h2",{id:"general-widgets"},"General Widgets"),(0,r.yg)("h3",{id:"clock"},"Clock"),(0,r.yg)("p",null,"A simple, live-updating time and date widget with time-zone support. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/vjb4RTv/clock.png"})),(0,r.yg)("h4",{id:"options"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"timeZone"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The time zone to display date and time in.",(0,r.yg)("br",null)," Specified as Region/City, for example: ",(0,r.yg)("inlineCode",{parentName:"td"},"Australia/Melbourne"),". See the ",(0,r.yg)("a",{parentName:"td",href:"https://timezonedb.com/time-zones"},"Time Zone DB")," for a full list of supported TZs. Defaults to the browser / device's local time")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"format"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A country code for displaying the date and time in local format.",(0,r.yg)("br",null),"Specified as ",(0,r.yg)("inlineCode",{parentName:"td"},"[ISO-3166]-[ISO-639]"),", for example: ",(0,r.yg)("inlineCode",{parentName:"td"},"en-AU"),". See ",(0,r.yg)("a",{parentName:"td",href:"https://www.fincher.org/Utilities/CountryLanguageList.shtml"},"here")," for a full list of locales. Defaults to the browser / device's region")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"customCityName"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default the city from the time-zone is shown, but setting this value will override that text")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideDate"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the date and city will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideSeconds"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", seconds will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"use12Hour"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", 12 hour time will be displayed. Defaults to the settings suggested by the current ",(0,r.yg)("inlineCode",{parentName:"td"},"format")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"timeZone"))))),(0,r.yg)("h4",{id:"example"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: clock\n options:\n timeZone: Europe/London\n format: en-GB\n hideDate: false\n")),(0,r.yg)("h4",{id:"info"},"Info"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No external data requests.")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"weather"},"Weather"),(0,r.yg)("p",null,"A simple, live-updating local weather component, showing temperature, conditions and more info."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/r6MCfsL/weather.png"})),(0,r.yg)("h4",{id:"options-1"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your OpenWeatherMap API key. You can get one for free at ",(0,r.yg)("a",{parentName:"td",href:"https://openweathermap.org/"},"openweathermap.org"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"city"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"units"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The units to use for displaying data, can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"metric")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"imperial"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"metric"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideDetails"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lat"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"To show weather for a specific location, you can provide the latitude and longitude coordinates. If provided, this will override the ",(0,r.yg)("inlineCode",{parentName:"td"},"city")," option")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lon"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"To show weather for a specific location, you can provide the latitude and longitude coordinates. If provided, this will override the ",(0,r.yg)("inlineCode",{parentName:"td"},"city")," option")))),(0,r.yg)("h4",{id:"example-1"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: weather\n options:\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n city: London\n units: metric\n hideDetails: true\n")),(0,r.yg)("h4",{id:"info-1"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://openweather.co.uk/privacy-policy"},"OWM Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"weather-forecast"},"Weather Forecast"),(0,r.yg)("p",null,"Displays the weather (temperature and conditions) for the next few days for a given location. Note that this requires either the free ",(0,r.yg)("a",{parentName:"p",href:"https://home.openweathermap.org/students"},"OpenWeatherMap Student Plan"),", or the Premium Plan."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/vshwgZB/weather-forecast.png"})),(0,r.yg)("h4",{id:"options-2"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your OpenWeatherMap API key. You can get one at ",(0,r.yg)("a",{parentName:"td",href:"https://openweathermap.org/"},"openweathermap.org")," or for free via the ",(0,r.yg)("a",{parentName:"td",href:"https://home.openweathermap.org/students"},"OWM Student Plan"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"city"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"numDays"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of days to display of forecast info to display. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"4"),", max ",(0,r.yg)("inlineCode",{parentName:"td"},"16")," days")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"units"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The units to use for displaying data, can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"metric")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"imperial"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"metric"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideDetails"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))))),(0,r.yg)("h4",{id:"example-2"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: weather-forecast\n options:\n city: California\n numDays: 6\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n units: imperial\n")),(0,r.yg)("h4",{id:"info-2"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udd34 Premium (free for personal use only)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://openweather.co.uk/privacy-policy"},"OWM Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"rss-feed"},"RSS Feed"),(0,r.yg)("p",null,"Display news and updates from any RSS-enabled service."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/N9mvLh4/rss-feed.png"})),(0,r.yg)("h4",{id:"options-3"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"rssUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL location of your RSS feed")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An API key for ",(0,r.yg)("a",{parentName:"td",href:"https://rss2json.com/"},"rss2json"),". It's free, and will allow you to make 10,000 requests per day, you can sign up ",(0,r.yg)("a",{parentName:"td",href:"https://rss2json.com/sign-up"},"here"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of posts to return. If you haven't specified an API key, this will be limited to 10")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"orderBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"How results should be sorted. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"pubDate"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"author")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"title"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"pubDate"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"orderDirection"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Order direction of feed items to return. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"asc")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"desc"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"desc"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"parseLocally"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If true parse the rss feed locally instead of using the rss2json API.")))),(0,r.yg)("h4",{id:"example-3"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: rss-feed\n options:\n rssUrl: https://www.schneier.com/blog/atom.xml\n apiKey: xxxx\n")),(0,r.yg)("h4",{id:"info-3"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free Plan (up to 10,000 requests / day)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://rss2json.com/privacy-policy"},"Rss2Json Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"image"},"Image"),(0,r.yg)("p",null,"Displays an image."),(0,r.yg)("p",null,"This may be useful if you have a service (such as Grafana - ",(0,r.yg)("a",{parentName:"p",href:"https://mattionline.de/grafana-api-export-graph-as-png/"},"see example"),"), which periodically exports charts or other data as an image."),(0,r.yg)("p",null,"You can also store images within Dashy's public directory (using a Docker volume), and reference them directly. E.g. ",(0,r.yg)("inlineCode",{parentName:"p"},"-v ./path/to/my-homelab-logo.png:/app/public/logo.png"),", then in the widget ",(0,r.yg)("inlineCode",{parentName:"p"},"imagePath: /logo.png"),"."),(0,r.yg)("p",null,"Similarly, any web service that serves up widgets as image can be used. E.g. you could show current star chart for a GitHub repo, with: ",(0,r.yg)("inlineCode",{parentName:"p"},"imagePath: https://starchart.cc/Lissy93/dashy.svg"),"."),(0,r.yg)("p",null,"If you'd like to embed a live screenshot, of all or just part of a website, then this can be done using ",(0,r.yg)("a",{parentName:"p",href:"https://apiflash.com/"},"API Flash"),"."),(0,r.yg)("p",null,"Or what about showing a photo of the day? Try ",(0,r.yg)("inlineCode",{parentName:"p"},"https://source.unsplash.com/random/400x300")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"https://picsum.photos/400/300")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"300",src:"https://i.ibb.co/P48Y443/image-widget.png"})),(0,r.yg)("h4",{id:"options-4"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"imagePath"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The path (local or remote) of the image to display")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"imageWidth"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify a fixed width for rendered image. Accepts either integer value in ",(0,r.yg)("inlineCode",{parentName:"td"},"px"),", or any string value with units (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"420"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"100px"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"6.9rem"),") (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"imageHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify a fixed height for rendered image. Accepts either integer value in ",(0,r.yg)("inlineCode",{parentName:"td"},"px"),", or any string value with units (e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"420"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"100px"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"6.9rem"),") (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"auto"),")")))),(0,r.yg)("h4",{id:"example-4"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: image\n options:\n imagePath: https://i.ibb.co/yhbt6CY/dashy.png\n")),(0,r.yg)("h4",{id:"info-4"},"Info"),(0,r.yg)("p",null,"Unless image fetched from remote source, no external data request is made."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"public-ip"},"Public IP"),(0,r.yg)("p",null,'Often find yourself searching "What\'s my IP", just so you can check your VPN is still connected? This widget displays your public IP address, along with ISP name and approx location. Data can be fetched from either ',(0,r.yg)("a",{parentName:"p",href:"https://ipapi.co/"},"IpApi.co"),", ",(0,r.yg)("a",{parentName:"p",href:"https://ip-api.com/"},"IP-API.com")," or ",(0,r.yg)("a",{parentName:"p",href:"https://ipgeolocation.io/"},"IpGeolocation.io"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/vc3c8zN/public-ip.png"})),(0,r.yg)("h4",{id:"options-5"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"All fields are optional.")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"provider"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The name of the service to fetch IP address from. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"ipapi.co"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"ip-api")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"ipgeolocation"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"ipapi.co"),". Note, ",(0,r.yg)("inlineCode",{parentName:"td"},"ip-api")," doesn't work on HTTPS, and if you set to ",(0,r.yg)("inlineCode",{parentName:"td"},"ipgeolocation")," then you must also provide an API key")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only required if provider is set to ",(0,r.yg)("inlineCode",{parentName:"td"},"ipgeolocation"),". You can get a free API key ",(0,r.yg)("a",{parentName:"td",href:"https://ipgeolocation.io/signup.html"},"here"))))),(0,r.yg)("h4",{id:"example-5"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: public-ip\n")),(0,r.yg)("p",null,"Or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: public-ip\n options:\n provider: ipgeolocation\n apiKey: xxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-5"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://ipgeolocation.io/privacy.html"},"IPGeoLocation Privacy Policy")," or ",(0,r.yg)("a",{parentName:"em",href:"https://ip-api.com/docs/legal"},"IP-API Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"ip-blacklist"},"IP Blacklist"),(0,r.yg)("p",null,"Notice certain web pages aren't loading? This widget quickly shows which blacklists your IP address (or host, or email) appears on, using data from ",(0,r.yg)("a",{parentName:"p",href:"https://blacklistchecker.com/"},"blacklistchecker.com"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/hX0fp5Z/ip-blacklist.png"})),(0,r.yg)("h4",{id:"options-6"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"ipAddress"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The IP to check. This can also be a domain/ host name or even an email address. If left blank, Dashy will use your current public IP address.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"You can get your free API key from ",(0,r.yg)("a",{parentName:"td",href:"https://blacklistchecker.com/keys"},"blacklistchecker.com"))))),(0,r.yg)("h4",{id:"example-6"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: blacklist-check\n options:\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n ipAddress: 1.1.1.1\n")),(0,r.yg)("h4",{id:"info-6"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free Plan"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://blacklistchecker.com/privacy"},"BlacklistChecker Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"domain-monitor"},"Domain Monitor"),(0,r.yg)("p",null,"Keep an eye on the expiry dates of your domain names, using public whois records fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://whoapi.com/"},"whoapi.com"),". Click the domain name to view additional info, like registrar, name servers and date last updated."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/7XjByG9/domain-monitor.png"})),(0,r.yg)("h4",{id:"options-7"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"domain"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The domain to check")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"You can get your free API key from ",(0,r.yg)("a",{parentName:"td",href:"https://my.whoapi.com/user/signup"},"my.whoapi.com"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showFullInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to true, the toggle-full-info panel will be open by default")))),(0,r.yg)("h4",{id:"example-7"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: domain-monitor\n options:\n domain: example.com\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n - type: domain-monitor\n options:\n domain: example2.com\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-7"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free Plan (10,000 requests)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://whoapi.com/privacy-policy/"},"WhoAPI Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"crypto-watch-list"},"Crypto Watch List"),(0,r.yg)("p",null,"Keep track of price changes of your favorite crypto assets. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://www.coingecko.com/"},"CoinGecko"),". All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/WtS6jQ8/crypto-prices.png"})),(0,r.yg)("h4",{id:"options-8"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"assets"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of cryptocurrencies, coins and tokens. See ",(0,r.yg)("a",{parentName:"td",href:"https://api.coingecko.com/api/v3/asset_platforms"},"list of supported assets"),". If none are specified, then the top coins by ",(0,r.yg)("inlineCode",{parentName:"td"},"sortBy")," (defaults to market cap) will be returned")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"currency"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The fiat currency to display price in, expressed as an ISO-4217 alpha code (see ",(0,r.yg)("a",{parentName:"td",href:"https://www.iban.com/currency-codes"},"list of currencies"),"). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"USD"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The method of sorting results. Can be ",(0,r.yg)("inlineCode",{parentName:"td"},"marketCap"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"volume")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"alphabetical"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"marketCap"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Number of results to return, useful when no assets are specified. Defaults to either ",(0,r.yg)("inlineCode",{parentName:"td"},"all")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"100"))))),(0,r.yg)("h4",{id:"example-8"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: crypto-watch-list\n options:\n limit: 10\n")),(0,r.yg)("p",null,"Or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: crypto-watch-list\n options:\n currency: GBP\n sortBy: marketCap\n assets:\n - bitcoin\n - ethereum\n - monero\n - cosmos\n - polkadot\n - dogecoin\n")),(0,r.yg)("h4",{id:"info-8"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.coingecko.com/en/privacy"},"CoinGecko Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"crypto-token-price-history"},"Crypto Token Price History"),(0,r.yg)("p",null,"Shows recent price history for a given crypto asset, using price data fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://www.coingecko.com/"},"CoinGecko")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/jr38m6S/crypto-price-history.png"})),(0,r.yg)("h4",{id:"options-9"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"asset"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Name of a crypto asset, coin or token to fetch price data for, see ",(0,r.yg)("a",{parentName:"td",href:"https://api.coingecko.com/api/v3/asset_platforms"},"list of supported assets"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"currency"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The fiat currency to display results in, expressed as an ISO-4217 alpha code (see ",(0,r.yg)("a",{parentName:"td",href:"https://www.iban.com/currency-codes"},"list of currencies"),"). Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"USD"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"numDays"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of days of price history to render. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"7"),", min: ",(0,r.yg)("inlineCode",{parentName:"td"},"1"),", max: ",(0,r.yg)("inlineCode",{parentName:"td"},"30")," days")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color")," which inherits dashboard primary color")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))))),(0,r.yg)("h4",{id:"example-9"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: crypto-price-chart\n options:\n asset: bitcoin\n currency: GBP\n numDays: 7\n")),(0,r.yg)("h4",{id:"info-9"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.coingecko.com/en/privacy"},"CoinGecko Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"wallet-balance"},"Wallet Balance"),(0,r.yg)("p",null,"Keep track of your crypto balances and see recent transactions. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://www.blockcypher.com/dev/"},"BlockCypher")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/27HG4nj/wallet-balances.png"})),(0,r.yg)("h4",{id:"options-10"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"coin"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Symbol of coin or asset, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"btc"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"eth")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"doge"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"address"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Address to monitor. This is your wallet's ",(0,r.yg)("strong",{parentName:"td"},"public")," / receiving address")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"network"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"To use a different network, other than mainnet. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"main"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of transactions to display. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"),", set to large number to show all")))),(0,r.yg)("h4",{id:"example-10"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: wallet-balance\n options:\n coin: btc\n address: 3853bSxupMjvxEYfwGDGAaLZhTKxB2vEVC\n")),(0,r.yg)("h4",{id:"info-10"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.blockcypher.com/privacy.html"},"BlockCypher Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"code-stats"},"Code Stats"),(0,r.yg)("p",null,"Display your coding summary. ",(0,r.yg)("a",{parentName:"p",href:"https://codestats.net/"},"Code::Stats")," is a free and open source app that aggregates statistics about your programming activity. Dashy supports both the public instance, as well as self-hosted versions."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/dc0DTBW/code-stats.png"})),(0,r.yg)("h4",{id:"options-11"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your CodeStats username")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If your self-hosting CodeStats, then supply the host name. By default it will use the public hosted instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"monthsToShow"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the number of months to render in the historical data chart. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"6"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideMeta"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide the meta section (username, level, all-time and recent XP)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideHistory"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide the historical calendar heat map")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideLanguages"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide the programming languages pie chart")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideMachines"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide the machines percentage chart")))),(0,r.yg)("h4",{id:"example-11"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: code-stats\n options:\n username: alicia\n")),(0,r.yg)("h4",{id:"info-11"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted or Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://codestats.net/tos#privacy"},"Code::Stats Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"mullvad-status"},"Mullvad Status"),(0,r.yg)("p",null,"Shows your Mullvad VPN connection status, as well as server info. Fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://mullvad.net/en/check/"},"am.i.mullvad.net")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/3BCb2YV/mullvad-check.png"})),(0,r.yg)("h4",{id:"options-12"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No Options.")),(0,r.yg)("h4",{id:"example-12"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: mullvad-status\n")),(0,r.yg)("h4",{id:"info-12"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://mullvad.net/en/help/privacy-policy/"},"Mullvad Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"anonaddy"},"AnonAddy"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://anonaddy.com/"},"AnonAddy")," is a free and open source mail forwarding service. Use it to protect your real email address, by using a different alias for each of your online accounts, and have all emails land in your normal inbox(es). Supports custom domains, email replies, PGP-encryption, multiple recipients and more"),(0,r.yg)("p",null,"This widget display email addresses / aliases from AnonAddy. Click an email address to copy to clipboard, or use the toggle switch to enable/ disable it. Shows usage stats (bandwidth, used aliases etc), as well as total messages received, blocked and sent. Works with both self-hosted and managed instances of AnonAddy."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/ZhfyRdV/anonaddy.png"})),(0,r.yg)("h4",{id:"options-13"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your AnonAddy API Key / Personal Access Token. You can generate this under ",(0,r.yg)("a",{parentName:"td",href:"https://app.anonaddy.com/settings"},"Account Settings"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If your self-hosting AnonAddy, then supply the host name. By default it will use the public hosted instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiVersion"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you're using an API version that is not version ",(0,r.yg)("inlineCode",{parentName:"td"},"v1"),", then specify it here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of emails shown per page. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the sort order for email addresses. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"updated_at"),". Can be either: ",(0,r.yg)("inlineCode",{parentName:"td"},"local_part"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"domain"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"email"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"emails_forwarded"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"emails_blocked"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"emails_replied"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"emails_sent"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"created_at"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"updated_at")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"deleted_at"),". Precede with a ",(0,r.yg)("inlineCode",{parentName:"td"},"-")," character to reverse order.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"searchTerm"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A search term to filter results by, will search the email, description and domain")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"disableControls"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Prevent any changes being made to account through the widget. User will not be able to enable or disable aliases through UI when this option is set")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideMeta"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Don't show account meta info (forward/ block count, quota usage etc)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideAliases"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Don't show email address / alias list. Will only show account meta info")))),(0,r.yg)("h4",{id:"example-13"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},' - type: anonaddy\n options:\n apiKey: "xxxxxxxxxxxxxxxxxxxxxxxx\\\n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\\n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"\n limit: 5\n sortBy: created_at\n disableControls: true\n')),(0,r.yg)("h4",{id:"info-13"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free for Self-Hosted / Free Plan available on managed instance or $1/month for premium"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted or Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://anonaddy.com/privacy/"},"AnonAddy Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"vulnerability-feed"},"Vulnerability Feed"),(0,r.yg)("p",null,"Keep track of recent security advisories and vulnerabilities, with optional filtering by score, exploits, vendor and product. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/DYJMpjp/vulnerability-feed.png"})),(0,r.yg)("h4",{id:"options-14"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortBy"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The sorting method. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"publish-date"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"last-update")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"cve-code"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"publish-date"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of results to fetch. Can be between ",(0,r.yg)("inlineCode",{parentName:"td"},"5")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"30"),", defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"minScore"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set, will only display results with a CVE score higher than the number specified. Can be a number between ",(0,r.yg)("inlineCode",{parentName:"td"},"0")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"9.9"),". By default, vulnerabilities of all CVE scores are shown")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hasExploit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", will only show results with active exploits. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"vendorId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only show results from a specific vendor, specified by ID. See ",(0,r.yg)("a",{parentName:"td",href:"https://www.cvedetails.com/vendor-search.php"},"Vendor Search")," for list of vendors. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"23")," (Debian), ",(0,r.yg)("inlineCode",{parentName:"td"},"26")," (Microsoft), ",(0,r.yg)("inlineCode",{parentName:"td"},"23682")," (CloudFlare)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"productId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only show results from a specific app or product, specified by ID. See ",(0,r.yg)("a",{parentName:"td",href:"https://www.cvedetails.com/product-search.php"},"Product Search")," for list of products. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"28125")," (Docker), ",(0,r.yg)("inlineCode",{parentName:"td"},"34622")," (NextCloud), ",(0,r.yg)("inlineCode",{parentName:"td"},"50211")," (Portainer), ",(0,r.yg)("inlineCode",{parentName:"td"},"95391")," (ProtonMail)")))),(0,r.yg)("h4",{id:"example-14"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: cve-vulnerabilities\n")),(0,r.yg)("p",null,"or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: cve-vulnerabilities\n options:\n sortBy: publish-date\n productId: 28125\n hasExploit: false\n minScore: 5\n limit: 30\n")),(0,r.yg)("h4",{id:"info-14"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.cvedetails.com/privacy.php"},"CVE Details Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"exchange-rates"},"Exchange Rates"),(0,r.yg)("p",null,"Display current FX rates in your native currency. Hover over a row to view more info, or click to show rates in that currency."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/fMdyLTB/exchange-rates.png"})),(0,r.yg)("h4",{id:"options-15"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"inputCurrency"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The base currency to show results in. Specified as a 3-letter ISO-4217 code, see ",(0,r.yg)("a",{parentName:"td",href:"https://www.exchangerate-api.com/docs/supported-currencies"},"here")," for the full list of supported currencies, and their symbols")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"outputCurrencies"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"List or currencies to show results for. Specified as a 3-letter ISO-4217 code, see ",(0,r.yg)("a",{parentName:"td",href:"https://www.exchangerate-api.com/docs/supported-currencies"},"here")," for the full list of supported currencies, and their symbols")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"API key for ",(0,r.yg)("a",{parentName:"td",href:"https://www.exchangerate-api.com/"},"exchangerate-api.com"),", usually a 24-digit alpha-numeric string. You can sign up for a free account ",(0,r.yg)("a",{parentName:"td",href:"https://app.exchangerate-api.com/sign-up"},"here"))))),(0,r.yg)("h4",{id:"example-15"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: exchange-rates\n options:\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxx\n inputCurrency: GBP\n outputCurrencies:\n - USD\n - JPY\n - HKD\n - KPW\n")),(0,r.yg)("h4",{id:"info-15"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 100,000 requests/ month)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.exchangerate-api.com/terms"},"ExchangeRateAPI Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"public-holidays"},"Public Holidays"),(0,r.yg)("p",null,"Counting down to the next day off work? This widget displays upcoming public holidays for your country. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"http://kayaposoft.com/enrico/"},"Enrico")),(0,r.yg)("p",null,"Note, config for this widget is case-sensetive (see ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/issues/1268"},"#1268"),")"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/VC6fZqn/public-holidays.png"})),(0,r.yg)("h4",{id:"options-16"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"country"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The country to fetch holiday data for, specified as a country code, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"GB")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"US"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"state"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"restrict a country to a specific state defined by ",(0,r.yg)("a",{parentName:"td",href:"https://en.wikipedia.org/wiki/ISO_3166-2"},"ISO_3166-2"),", e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"LND"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"holidayType"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The type of holidays to fetch. Can be: ",(0,r.yg)("inlineCode",{parentName:"td"},"all"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"public_holiday"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"observance"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"school_holiday"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"other_day")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"extra_working_day"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"public_holiday"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"monthsToShow"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of months in advance to show. Min: ",(0,r.yg)("inlineCode",{parentName:"td"},"1"),", max: ",(0,r.yg)("inlineCode",{parentName:"td"},"24"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"12"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lang"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The language in which the events should be. Usually local languages and english are available. Default to first available in the country. e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"en")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"fr"),".")))),(0,r.yg)("h4",{id:"example-16"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: public-holidays\n options:\n country: GB\n region: LND\n holidayType: all\n monthsToShow: 12\n lang: en\n")),(0,r.yg)("h4",{id:"info-16"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jurajmajer/enrico"},"jurajmajer/enrico"),") or Managed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"covid-19-status"},"Covid-19 Status"),(0,r.yg)("p",null,"Keep track of the current COVID-19 status. Optionally also show cases by country, and a time-series chart. Uses live data from various sources, computed by ",(0,r.yg)("a",{parentName:"p",href:"https://disease.sh/"},"disease.sh")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/7XjbyRg/covid-19-status.png?"})),(0,r.yg)("h4",{id:"options-17"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showChart"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Also display a time-series chart showing number of recent cases")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showCountries"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Also display a list of cases per country")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"numDays"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify number of days worth of history to render on the chart")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"countries"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string[]")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"An array of countries to display, specified by their ",(0,r.yg)("a",{parentName:"td",href:"https://www.iso.org/obp/ui"},"ISO-3 codes"),". Leave blank to show all, sorted by most cases. ",(0,r.yg)("inlineCode",{parentName:"td"},"showCountries")," must be set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If showing all countries, set a limit for number of results to return. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"),", no maximum")))),(0,r.yg)("h4",{id:"example-17"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: covid-stats\n")),(0,r.yg)("p",null,"Or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: covid-stats\n options:\n showChart: true\n showCountries: true\n countries:\n - GBR\n - USA\n - IND\n - RUS\n")),(0,r.yg)("h4",{id:"info-17"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/disease-sh/api"},"disease-sh/api"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Conditions"),": ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/disease-sh/api/blob/master/TERMS.md"},"Terms of Use"))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"sports-scores"},"Sports Scores"),(0,r.yg)("p",null,"Show recent scores and upcoming matches from your favourite sports team. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://www.thesportsdb.com/"},"TheSportsDB.com"),". From the UI, you can click any other team to view their scores and upcoming games, or click a league name to see all teams."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/8XhXGkN/sports-scores.png"})),(0,r.yg)("h4",{id:"options-18"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"teamId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The ID of a team to fetch scores from. You can search for your team on the ",(0,r.yg)("a",{parentName:"td",href:"https://www.thesportsdb.com/teams_main.php"},"Teams Page"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"leagueId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Alternatively, provide a league ID to fetch all games from. You can find the ID on the ",(0,r.yg)("a",{parentName:"td",href:"https://www.thesportsdb.com/Sport/Leagues"},"Leagues Page"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"pastOrFuture"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set to ",(0,r.yg)("inlineCode",{parentName:"td"},"past")," to show scores for recent games, or ",(0,r.yg)("inlineCode",{parentName:"td"},"future")," to show upcoming games. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"past"),". You can change this within the UI")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally specify your API key, which you can sign up for at ",(0,r.yg)("a",{parentName:"td",href:"https://www.thesportsdb.com/"},"TheSportsDB.com"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"To limit output to a certain number of matches, defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"15"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideImage"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," to not render the team / match banner image, defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))))),(0,r.yg)("h4",{id:"example-18"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: sports-scores\n options:\n teamId: 133636\n")),(0,r.yg)("h4",{id:"info-18"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 30 requests / minute, limited endpoints)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"news-headlines"},"News Headlines"),(0,r.yg)("p",null,"Displays the latest news, click to read full article. Date is fetched from various news sources using ",(0,r.yg)("a",{parentName:"p",href:"https://currentsapi.services/en"},"Currents API")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/6NDWW0z/news-headlines.png"})),(0,r.yg)("h4",{id:"options-19"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your API key for CurrentsAPI. This is free, and you can ",(0,r.yg)("a",{parentName:"td",href:"https://currentsapi.services/en/register"},"get one here"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"country"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Fetch news only from a certain country or region. Specified as a country code, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"GB")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"US"),". See ",(0,r.yg)("a",{parentName:"td",href:"https://api.currentsapi.services/v1/available/regions"},"here")," for a list of supported regions")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"category"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only return news from within a given category, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"sports"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"programming"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"world"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"science"),". The ",(0,r.yg)("a",{parentName:"td",href:"https://api.currentsapi.services/v1/available/categories"},"following categories")," are supported")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lang"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the language for returned articles as a 2-digit ISO code (limited article support). The ",(0,r.yg)("a",{parentName:"td",href:"https://api.currentsapi.services/v1/available/languages"},"following languages")," are supported, defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"en"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"count"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of results. Can be between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"200"),", defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"keywords"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Only return articles that contain an exact match within their title or description")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideImages"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", then article image thumbnails will not be displayed")))),(0,r.yg)("h4",{id:"example-19"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: news-headlines\n options:\n apiKey: xxxxxxx\n category: world\n")),(0,r.yg)("h4",{id:"info-19"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 600 requests / day)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://currentsapi.services/privacy"},"CurrentsAPI Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"tfl-status"},"TFL Status"),(0,r.yg)("p",null,"Shows real-time tube status of the London Underground. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/LRDhXDn/tfl-status.png"})),(0,r.yg)("h4",{id:"options-20"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showAll"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default, details for lines with a Good Service are not visible, but you can click More Details to see all. Setting this option to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," will show all lines on initial page load")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sortAlphabetically"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default lines are sorted by current status, set this option to ",(0,r.yg)("inlineCode",{parentName:"td"},"true")," to instead sort them alphabetically")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"linesToShow"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default all lines are shown. If you're only interested in the status of a few lines, then pass in an array of lines to show, specified by name")))),(0,r.yg)("h4",{id:"example-20"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: tfl-status\n")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: tfl-status\n options:\n showAll: true\n sortAlphabetically: true\n linesToShow:\n - District\n - Jubilee\n - Central\n")),(0,r.yg)("h4",{id:"info-20"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://tfl.gov.uk/corporate/privacy-and-cookies/"},"TFL Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"stock-price-history"},"Stock Price History"),(0,r.yg)("p",null,"Shows recent price history for a given publicly-traded stock or share"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/XZHRb4f/stock-price.png"})),(0,r.yg)("h4",{id:"options-21"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"API key for ",(0,r.yg)("a",{parentName:"td",href:"https://www.alphavantage.co/"},"Alpha Vantage"),", you can get a free API key ",(0,r.yg)("a",{parentName:"td",href:"https://www.alphavantage.co/support/#api-key"},"here"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"stock"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The stock symbol for the asset to fetch data for")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"priceTime"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The time to fetch price for. Can be ",(0,r.yg)("inlineCode",{parentName:"td"},"high"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"low"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"open")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"close"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"high"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color")," which inherits dashboard primary color")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))))),(0,r.yg)("h4",{id:"example-21"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: stock-price-chart\n options:\n stock: NET\n apiKey: PGUWSWD6CZTXMT8N\n")),(0,r.yg)("h4",{id:"info-21"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 500 requests/day)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.alphavantage.co/privacy/"},"AlphaVantage Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"eth-gas-prices"},"ETH Gas Prices"),(0,r.yg)("p",null,"Renders the current Gas cost of transactions on the Ethereum network (in both GWEI and USD), along with recent historical prices. Useful for spotting a good time to transact. Uses data from ",(0,r.yg)("a",{parentName:"p",href:"https://ethgas.watch/"},"ethgas.watch")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/LhHfQyp/eth-gas-prices.png"})),(0,r.yg)("h4",{id:"options-22"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No config options.")),(0,r.yg)("h4",{id:"example-22"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: eth-gas-prices\n")),(0,r.yg)("h4",{id:"info-22"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/wslyvh/ethgaswatch"},"wslyvh/ethgaswatch"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"joke"},"Joke"),(0,r.yg)("p",null,"Renders a programming or generic joke. Data is fetched from the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Sv443/JokeAPI"},"JokesAPI")," by @Sv443. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/sQJGkyR/joke.png"})),(0,r.yg)("h4",{id:"options-23"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"category"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set the category of jokes to return. Use a string to specify a single category, or an array to pass in multiple options. Available options are: ",(0,r.yg)("inlineCode",{parentName:"td"},"all"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"programming"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"pun"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"dark"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"spooky"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"christmas")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"misc"),". An up-to-date list of supported categories can be found ",(0,r.yg)("a",{parentName:"td",href:"https://v2.jokeapi.dev/categories"},"here"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"all"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"safeMode"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", to prevent the fetching of any NSFW jokes. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"language"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the language for returned jokes. The following languages are supported: ",(0,r.yg)("inlineCode",{parentName:"td"},"en"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"cs"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"de"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"es"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"fr")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"pt"),", and an up-to-date list of supported languages can be found ",(0,r.yg)("a",{parentName:"td",href:"https://v2.jokeapi.dev/languages"},"here"),". By default, your system language will be used, if it's supported, otherwise English")))),(0,r.yg)("h4",{id:"example-23"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: joke\n options:\n safeMode: true\n language: en\n category: Programming\n")),(0,r.yg)("h4",{id:"info-23"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Sv443/JokeAPI"},"Sv443/JokeAPI"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://sv443.net/privacypolicy/en"},"SV443's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"xkcd-comics"},"XKCD Comics"),(0,r.yg)("p",null,"Have a laugh with the daily comic from ",(0,r.yg)("a",{parentName:"p",href:"https://xkcd.com/"},"XKCD"),". A classic webcomic website covering everything from Linux, math, romance, science and language. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/kqV68hy/xkcd-comic.png"})),(0,r.yg)("h4",{id:"options-24"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"comic"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string / number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Choose which comic to display. Set to either ",(0,r.yg)("inlineCode",{parentName:"td"},"random"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"latest")," or the series number of a specific comic, like ",(0,r.yg)("inlineCode",{parentName:"td"},"627"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"latest"))))),(0,r.yg)("h4",{id:"example-24"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: xkcd-comic\n options:\n comic: latest\n")),(0,r.yg)("h4",{id:"info-24"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"flight-data"},"Flight Data"),(0,r.yg)("p",null,"Displays airport departure and arrival flights, using data from ",(0,r.yg)("a",{parentName:"p",href:"https://www.aerodatabox.com/"},"AeroDataBox"),". Useful if you live near an airport and often wonder where the flight overhead is going to. Hover over a row for more flight data."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/yPMBJSY/flight-data.png"})),(0,r.yg)("h4",{id:"options-25"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"airport"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The airport to show flight data from. Should be specified as a 4-character ICAO-code, a full list of which can be found ",(0,r.yg)("a",{parentName:"td",href:"https://en.wikipedia.org/wiki/ICAO_airport_code"},"here")," (example: ",(0,r.yg)("inlineCode",{parentName:"td"},"KBJC")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"EGKK"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A valid ",(0,r.yg)("a",{parentName:"td",href:"https://rapidapi.com/"},"RapidAPI")," Key, with ",(0,r.yg)("a",{parentName:"td",href:"https://rapidapi.com/aerodatabox/api/aerodatabox/"},"AeroDataBox")," enabled (check in your ",(0,r.yg)("a",{parentName:"td",href:"https://rapidapi.com/developer/billing/subscriptions-and-usage"},"Subscription Dashboard"),"). This API is free to sign up for and use")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"For busy airports, you may wish to limit the number of results visible")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"direction"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"By default, both departure and arrival flights will be fetched, if you would like to only show flights in one direction, set this to wither ",(0,r.yg)("inlineCode",{parentName:"td"},"departure")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"arrival"))))),(0,r.yg)("h4",{id:"example-25"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: flight-data\n options:\n airport: EGLC\n apiKey: XXXXX\n limit: 12\n direction: all\n")),(0,r.yg)("h4",{id:"info-25"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 150 requests / month)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance Only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.aerodatabox.com/#h.p_CXtIYZWF_WQd"},"AeroDataBox")," and ",(0,r.yg)("a",{parentName:"em",href:"https://rapidapi.com/privacy/"},"RapidAPI Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"astronomy-picture-of-the-day"},"Astronomy Picture of the Day"),(0,r.yg)("p",null,"Show the NASA Astronomy Picture of the Day. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://apod.nasa.gov/apod/"},"APOD")," using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/lissy93/go-apod"},"@Lissy93/go-apod")," / hosted at ",(0,r.yg)("a",{parentName:"p",href:"https://apod.as93.net/"},"apod.as93.net"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/ZMkgLFK/apod.png"})),(0,r.yg)("h4",{id:"options-26"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No config options.")),(0,r.yg)("h4",{id:"example-26"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: apod\n")),(0,r.yg)("h4",{id:"info-26"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/lissy93/go-apod"},"@Lissy93/go-apod"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.nasa.gov/about/highlights/HP_Privacy.html"},"NASA's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"github-trending"},"GitHub Trending"),(0,r.yg)("p",null,"Displays currently trending projects on GitHub. Optionally specify a language and time-frame. Data is fetched from ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/gh-trending-no-cors"},"Lissy93/gh-trending-no-cors")," using the GitHub API. All fields are optional."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/BGy7Q3g/github-trending.png"})),(0,r.yg)("h4",{id:"options-27"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"lang"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A programming language to fetch trending repos from that category. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"javascript")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"go"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"since"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The timeframe to use when calculating trends. Can be either ",(0,r.yg)("inlineCode",{parentName:"td"},"daily"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"weekly")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"monthly"),". Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"daily"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally limit the number of results. Max ",(0,r.yg)("inlineCode",{parentName:"td"},"25"),", default is ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))))),(0,r.yg)("h4",{id:"example-27"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: github-trending-repos\n options:\n limit: 8\n since: weekly\n")),(0,r.yg)("h4",{id:"info-27"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Lissy93/gh-trending-no-cors"},"Lissy93/gh-trending-no-cors"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://docs.github.com/en/github/site-policy/github-privacy-statement"},"GitHub's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"github-profile-stats"},"GitHub Profile Stats"),(0,r.yg)("p",null,"Display stats from your GitHub profile, using embedded cards from ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/anuraghazra/github-readme-stats"},"anuraghazra/github-readme-stats")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/L0K1zNN/github-profile-stats.png"})),(0,r.yg)("h4",{id:"options-28"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The GitHub username to fetch info for. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"lissy93"),". (Not required if ",(0,r.yg)("inlineCode",{parentName:"td"},"hideProfileCard")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"hideLanguagesCard")," are both set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideProfileCard"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the users profile card will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideLanguagesCard"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", the users top languages card will not be shown. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"false"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"repos"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you'd like to also display stats for some GitHub repositories, then add an array or repo names here. Specified as ",(0,r.yg)("inlineCode",{parentName:"td"},"[username]/[repo-name]"),", e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"lissy93/dashy"))))),(0,r.yg)("h4",{id:"example-28"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: github-profile-stats\n options:\n username: Lissy93\n hideLanguagesCard: true\n repos:\n - lissy93/dashy\n - lissy93/personal-security-checklist\n - lissy93/twitter-sentiment-visualisation\n")),(0,r.yg)("h4",{id:"info-28"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/anuraghazra/github-readme-stats"},"anuraghazra/github-readme-stats"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://docs.github.com/en/github/site-policy/github-privacy-statement"},"GitHub's Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"healthchecks-status"},"HealthChecks Status"),(0,r.yg)("p",null,"Display status of one or more HealthChecks project(s). Works with healthchecks.io and your selfhosted instance."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/W5dP6VN/Bildschirm-foto-2023-01-07-um-11-07-11.png"})),(0,r.yg)("h4",{id:"options-29"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional"),(0,r.yg)("td",{parentName:"tr",align:null},"The base url of your instance, default is ",(0,r.yg)("inlineCode",{parentName:"td"},"https://healthchecks.io"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"One or more API keys for your healthcheck projects. (Read-only works fine)")))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: HealthChecks\n options:\n host: https://healthcheck.your-domain.de\n apiKey: \n - abcdefg...\n - zxywvu...\n")),(0,r.yg)("h4",{id:"info-29"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free / Paid / Self-hosted "),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/healthchecks/healthchecks"},"healthchecks/healthchecks"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://healthchecks.io/privacy/"},"Healthchecks.io Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"hackernews-trending"},"Hackernews Trending"),(0,r.yg)("p",null,"Display new and trending Posts from Hackernews"),(0,r.yg)("h4",{id:"options-30"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"stories"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"HN Stories to display defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"topstories"),". Options are: ",(0,r.yg)("inlineCode",{parentName:"td"},"beststories"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"topstories")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"newstories"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"int")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The size of the list of Posts to show.")))),(0,r.yg)("h5",{id:"example-29"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: hackernews-trending\n options:\n stories: newstories\n limit: 10\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"mvg-departure"},"MVG Departure"),(0,r.yg)("p",null,"Display departure time of a MVG (M\xfcnchner Verkehrs Gesellschaft) station."),(0,r.yg)("p",null,"From ",(0,r.yg)("a",{parentName:"p",href:"https://www.mvg.de/impressum.html"},"https://www.mvg.de/impressum.html"),":"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"[...]"," Die Verarbeitung unserer Inhalte oder Daten durch Dritte erfordert unsere ausdr\xfcckliche Zustimmung. F\xfcr private, nicht-kommerzielle Zwecke, wird eine gem\xe4\xdfigte Nutzung ohne unsere ausdr\xfcckliche Zustimmung geduldet. Jegliche Form von Data-Mining stellt keine gem\xe4\xdfigte Nutzung dar.","[...]")),(0,r.yg)("p",null,"In other words: Private, noncomercial, moderate use of the API is tolerated. They don\u2019t consider data mining as moderate use. (This is not a legal advice)"),(0,r.yg)("h4",{id:"options-31"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"location"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The name of the location (exact) or the location id, startin with ",(0,r.yg)("inlineCode",{parentName:"td"},"de:09162:"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"integer")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit number of entries, defaults to 10.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A custom title to be displayed.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"header"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"bool")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Shall the title be shown?")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.line"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for given line(s).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.product"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for specific product (TRAM, UBAHN, SBAHN, BUS).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.destination"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for specific destination(s)")))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: mvg\n options:\n location: Marienplatz\n limit: 5\n")),(0,r.yg)("h4",{id:"info-30"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free / Private use only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": ",(0,r.yg)("a",{parentName:"li",href:"https://mvg.de"},"MVG")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.mvg.de/datenschutz-mvg.html"},"MVG Datenschutz")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"mvg-connection"},"MVG Connection"),(0,r.yg)("p",null,"Display the next connection for two addresses/coordinates, stations or POI within Munich using MVG MVG (M\xfcnchner Verkehrs Gesellschaft)."),(0,r.yg)("p",null,"From ",(0,r.yg)("a",{parentName:"p",href:"https://www.mvg.de/impressum.html"},"https://www.mvg.de/impressum.html"),":"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},"[...]"," Die Verarbeitung unserer Inhalte oder Daten durch Dritte erfordert unsere ausdr\xfcckliche Zustimmung. F\xfcr private, nicht-kommerzielle Zwecke, wird eine gem\xe4\xdfigte Nutzung ohne unsere ausdr\xfcckliche Zustimmung geduldet. Jegliche Form von Data-Mining stellt keine gem\xe4\xdfigte Nutzung dar.","[...]")),(0,r.yg)("p",null,"In other words: Private, noncomercial, moderate use of the API is tolerated. They don\u2019t consider data mining as moderate use. (This is not a legal advice)"),(0,r.yg)("h4",{id:"options-32"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"origin"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Origin of the connection.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"destination"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Destination of the connection.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A custom title to be displayed.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"header"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"bool")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Shall the title be shown?")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.line"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for given line(s).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.product"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for specific product (TRAM, UBAHN, SBAHN, BUS).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"filters.destination"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string/object")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter results for specific destination(s)")))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: mvg-connection\n options:\n from: Marienplatz\n from: Dachauer Stra\xdfe 123\n header: true\n filters:\n product: [UBAHN]\n line: [U1,U2,U4,U5]\n\n")),(0,r.yg)("h4",{id:"info-31"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free / Private use only"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": ",(0,r.yg)("a",{parentName:"li",href:"https://mvg.de"},"MVG")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.mvg.de/datenschutz-mvg.html"},"MVG Datenschutz")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"custom-search"},"Custom search"),(0,r.yg)("p",null,"Allows web search using multiple user-defined search engines and other websites."),(0,r.yg)("h4",{id:"options-33"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"engines"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"required"),(0,r.yg)("td",{parentName:"tr",align:null},"An array of search engine objects. Each search engine object should have two required properties: ",(0,r.yg)("strong",{parentName:"td"},"title")," and ",(0,r.yg)("strong",{parentName:"td"},"url"),". See the example below.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"placeholder"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"Placeholder text in the search box.")))),(0,r.yg)("h4",{id:"notes"},"Notes"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"The first search engine in the engines array will be treated as the default search engine, and used when the user presses ",(0,r.yg)("inlineCode",{parentName:"li"},"Enter")," in the search box."),(0,r.yg)("li",{parentName:"ul"},"Popup blockers can interfere with opening a new search window.")),(0,r.yg)("h4",{id:"example-30"},"Example"),(0,r.yg)("p",null,"This widget allows searching multiple search engines from dashy."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: 'custom-search'\n options:\n placeholder: Search for something using the buttons below\n engines:\n - title: SearXNG\n url: https://searx.lan/?q=\n - title: Quant\n url: https://www.qwant.com/?q=\n - title: Bing Web\n url: http://www.bing.com/search?q=\n - title: Bing Images\n url: http://www.bing.com/images/search?q=\n - title: Bing Maps\n url: http://www.bing.com/maps/search?q=\n - title: Yandex\n url: https://www.yandex.com/search/?text=\n - title: Passmark\n url: https://www.passmark.com/search/zoomsearch.php?zoom_query=\n - title: IMDB\n url: http://www.imdb.com/find?q=\n")),(0,r.yg)("h4",{id:"info-32"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Not needed"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free "),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": user defined"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": depends on the user defined search engines.")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"rescuetime-overview"},"RescueTime Overview"),(0,r.yg)("p",null,"Show an overview of how you have spent your time for the current day."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/bvx3PQM/rescuetime.png"})),(0,r.yg)("h4",{id:"options-34"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"required"),(0,r.yg)("td",{parentName:"tr",align:null},"The API-Key generated in the RescueTime UI.")))),(0,r.yg)("h4",{id:"example-31"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: rescue-time\n useProxy: true\n options:\n apiKey: abcdefghijkl_mnop\n")),(0,r.yg)("h4",{id:"info-33"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Depends on user subscription "),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": ",(0,r.yg)("a",{parentName:"li",href:"https://www.rescuetime.com"},"RescueTime")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.rescuetime.com/privacy"},"RescueTime Privacy")))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"self-hosted-services-widgets"},"Self-Hosted Services Widgets"),(0,r.yg)("h3",{id:"system-info"},"System Info"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.mvg.de/datenschutz-mvg.html"},"MVG Datenschutz")),"\nDisplays info about the server which Dashy is hosted on. Includes user + host, operating system, uptime and basic memory & load data."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/rvDPBDF/system-info.png"})),(0,r.yg)("h4",{id:"options-35"},"Options"),(0,r.yg)("p",null,(0,r.yg)("em",{parentName:"p"},"No config options.")),(0,r.yg)("h4",{id:"example-32"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: system-info\n")),(0,r.yg)("h4",{id:"info-34"},"Info"),(0,r.yg)("p",null,"No external data requests made"),(0,r.yg)("p",null,"Note that this widget is not available if you are running Dashy in a container or VM. Instead you can use the ",(0,r.yg)("a",{parentName:"p",href:"#system-resource-monitoring"},"System Monitoring")," widgets to display stats from the host system instead."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cron-monitoring-health-checks"},"Cron Monitoring (Health Checks)"),(0,r.yg)("p",null,"Cron job monitoring using ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/healthchecks/healthchecks"},"Health Checks"),". Both managed and self-hosted instances are supported."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/Ptf2kwm/health-checks.png"})),(0,r.yg)("h4",{id:"options-36"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A read-only API key for the project to monitor. You can generate this by selecting a Project --\x3e Settings --\x3e API Access. Note that you must generate a separate key for each project")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you're self-hosting, or using any instance other than the official (healthchecks.io), you will need to specify the host address. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"https://healthchecks.example.com")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"http://cron-monitoing.local"))))),(0,r.yg)("h4",{id:"example-33"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: health-checks\n options:\n apiKey: XXXXXXXXX\n")),(0,r.yg)("h4",{id:"info-35"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe0 Free plan (up to 20 services, or self-host for unlimited)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Managed Instance or Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/healthchecks/healthchecks"},"GitHub - HealthChecks"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://healthchecks.io/privacy/"},"Health-Checks Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cpu-history-netdata"},"CPU History (NetData)"),(0,r.yg)("p",null,"Pull recent CPU usage history from NetData."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/ZdyR5nJ/nd-cpu-history.png"})),(0,r.yg)("h4",{id:"options-37"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your NetData instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," / ",(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value(s) as hex codes. ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColor")," is a single value (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color"),"), whereas ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColors")," is an array of colors")))),(0,r.yg)("h4",{id:"example-34"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nd-cpu-history\n options:\n host: http://192.168.1.1:19999\n")),(0,r.yg)("h4",{id:"info-36"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/netdata/netdata"},"GitHub - NetData"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.netdata.cloud/data-privacy/"},"NetData Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"memory-history-netdata"},"Memory History (NetData)"),(0,r.yg)("p",null,"Pull recent system RAM usage from NetData, and show as a breakdown of different categories."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/2dsSWnk/nd-memory-history.png"})),(0,r.yg)("h4",{id:"options-38"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your NetData instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," / ",(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value(s) as hex codes. ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColor")," is a single value (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color"),"), whereas ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColors")," is an array of colors")))),(0,r.yg)("h4",{id:"example-35"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nd-ram-history\n options:\n host: http://192.168.1.1:19999\n")),(0,r.yg)("h4",{id:"info-37"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/netdata/netdata"},"GitHub - NetData"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.netdata.cloud/data-privacy/"},"NetData Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"load-history-netdata"},"Load History (NetData)"),(0,r.yg)("p",null,"Pull recent load usage in 1, 5 and 15 minute intervals, from NetData."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/qR9C2tJ/nd-load-history.png"})),(0,r.yg)("h4",{id:"options-39"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your NetData instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The height of rendered chart in px. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"300"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColor"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"chartColors"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")," / ",(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Color of the chart value(s) as hex codes. ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColor")," is a single value (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"--widget-text-color"),"), whereas ",(0,r.yg)("inlineCode",{parentName:"td"},"chartColors")," is an array of colors")))),(0,r.yg)("h4",{id:"example-36"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nd-load-history\n options:\n host: http://192.168.1.1:19999\n")),(0,r.yg)("h4",{id:"info-38"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/netdata/netdata"},"GitHub - NetData"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.netdata.cloud/data-privacy/"},"NetData Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"pi-hole-stats"},"Pi Hole Stats"),(0,r.yg)("p",null,"Displays the number of queries blocked by ",(0,r.yg)("a",{parentName:"p",href:"https://pi-hole.net/"},"Pi-Hole"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/zftCLJN/pi-hole-stats.png"})),(0,r.yg)("h4",{id:"options-40"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your Pi-Hole instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideStatus"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideChart"))," / ",(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Optionally hide any of the three parts of the widget")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your Pi-Hole web password. It is ",(0,r.yg)("strong",{parentName:"td"},"NOT")," your pi-hole admin interface or server password. It can be found in ",(0,r.yg)("inlineCode",{parentName:"td"},"/etc/pihole/setupVars.conf"),", and is a 64-character located on the line that starts with ",(0,r.yg)("inlineCode",{parentName:"td"},"WEBPASSWORD"))))),(0,r.yg)("h4",{id:"example-37"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: pi-hole-stats\n options:\n hostname: http://192.168.130.1\n apiKey: xxxxxxxxxxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-39"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pi-hole/pi-hole"},"GitHub - Pi-hole"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://pi-hole.net/privacy/"},"Pi-Hole Privacy Guide")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"pi-hole-queries"},"Pi Hole Queries"),(0,r.yg)("p",null,"Shows top queries that were blocked and allowed by ",(0,r.yg)("a",{parentName:"p",href:"https://pi-hole.net/"},"Pi-Hole"),"."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/pXR0bdQ/pi-hole-queries.png"})),(0,r.yg)("h4",{id:"options-41"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your Pi-Hole instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your Pi-Hole web password. It is ",(0,r.yg)("strong",{parentName:"td"},"NOT")," your pi-hole admin interface or server password. It can be found in ",(0,r.yg)("inlineCode",{parentName:"td"},"/etc/pihole/setupVars.conf"),", and is a 64-character located on the line that starts with ",(0,r.yg)("inlineCode",{parentName:"td"},"WEBPASSWORD"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"count"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"The number of queries to display. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))))),(0,r.yg)("h4",{id:"example-38"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: pi-hole-top-queries\n options:\n hostname: https://pi-hole.local\n apiKey: xxxxxxxxxxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-40"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pi-hole/pi-hole"},"GitHub - Pi-hole"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://pi-hole.net/privacy/"},"Pi-Hole Privacy Guide")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"pi-hole-recent-traffic"},"Pi Hole Recent Traffic"),(0,r.yg)("p",null,"Shows number of recent traffic, using allowed and blocked queries from ",(0,r.yg)("a",{parentName:"p",href:"https://pi-hole.net/"},"Pi-Hole")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/7kdxxwx/pi-hole-recent-queries.png"})),(0,r.yg)("h4",{id:"options-42"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your Pi-Hole instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Your Pi-Hole web password. It is ",(0,r.yg)("strong",{parentName:"td"},"NOT")," your pi-hole admin interface or server password. It can be found in ",(0,r.yg)("inlineCode",{parentName:"td"},"/etc/pihole/setupVars.conf"),", and is a 64-character located on the line that starts with ",(0,r.yg)("inlineCode",{parentName:"td"},"WEBPASSWORD"))))),(0,r.yg)("h4",{id:"example-39"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: pi-hole-traffic\n options:\n hostname: https://pi-hole.local\n apiKey: xxxxxxxxxxxxxxxxxxxxxxx\n")),(0,r.yg)("h4",{id:"info-41"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udd34 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pi-hole/pi-hole"},"GitHub - Pi-hole"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://pi-hole.net/privacy/"},"Pi-Hole Privacy Guide")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"stat-ping-statuses"},"Stat Ping Statuses"),(0,r.yg)("p",null,"Displays the current and recent uptime of your running services, via a self-hosted instance of ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/statping/statping"},"StatPing")),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"300",src:"https://i.ibb.co/Fq7JDjQ/stat-ping.png"})),(0,r.yg)("h4",{id:"options-43"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your StatPing instance, without a trailing slash")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"groupId"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional"),(0,r.yg)("td",{parentName:"tr",align:null},"If provided, only Services in the given group are displayed. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"0")," in which case all services are displayed.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showChart"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional"),(0,r.yg)("td",{parentName:"tr",align:null},"If provided and ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," then charts are not displayed. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"Optional"),(0,r.yg)("td",{parentName:"tr",align:null},"If provided and ",(0,r.yg)("inlineCode",{parentName:"td"},"false")," then information summaries are not displayed. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),".")))),(0,r.yg)("h4",{id:"example-40"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: stat-ping\n options:\n hostname: http://192.168.130.1:8080\n")),(0,r.yg)("p",null,"or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: stat-ping\n options:\n hostname: http://192.168.130.1:8080\n groupId: 3\n showChart: false\n showInfo: false\n")),(0,r.yg)("p",null,"You can use multiple StatPing widgets with different ",(0,r.yg)("inlineCode",{parentName:"p"},"groupId"),"s."),(0,r.yg)("p",null,"Note, the Group Id is not directly visible in StatPing UI, you can inspect the group select HTML element or the API response to find out."),(0,r.yg)("h4",{id:"info-42"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Not Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/statping/statping"},"GitHub - StatPing"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://docs.statping.com/"},"StatPing Docs")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"synology-download-station"},"Synology Download Station"),(0,r.yg)("p",null,"Displays the current downloads/torrents tasks of your Synology NAS"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/N2kKWTN/image.png"})),(0,r.yg)("h4",{id:"options-44"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your Synology NAS, without a trailing slash")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The username of a user on your synology NAS. You will see only this user download station tasks if he is not part of the administrator group. Currently don't support OTP protected accounts.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The password of the account specified above.")))),(0,r.yg)("h4",{id:"example-41"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: synology-download\n options:\n hostname: http://192.168.1.1:8080\n username: dashy\n password: totally-secure-password\n\n\n")),(0,r.yg)("h4",{id:"info-43"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://www.synology.com/en-us"},"Synology"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.synology.com/en-us/company/legal/privacy"},"Synology Privacy Statement")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adguard-home-block-stats"},"AdGuard Home Block Stats"),(0,r.yg)("p",null,"Fetches data from your ",(0,r.yg)("a",{parentName:"p",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home")," instance, and\ndisplays total number of allowed and blocked queries, plus a pie chart showing breakdown by block type."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/qgkcxsN/adguard-block-percent-2.png"})),(0,r.yg)("h4",{id:"options-45"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your AdGuard Home instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your username here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your password here")))),(0,r.yg)("h4",{id:"example-42"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: adguard-stats\n useProxy: true\n options:\n hostname: http://127.0.0.1\n username: admin\n password: test\n")),(0,r.yg)("h4",{id:"info-44"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://adguard.com/en/privacy.html"},"AdGuard Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adguard-home-filters"},"AdGuard Home Filters"),(0,r.yg)("p",null,"Fetches data from your ",(0,r.yg)("a",{parentName:"p",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home")," instance, to display the current status of each of your filter lists. Includes filter name, last updated, number of items, and a link to the list."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/WsJkf5g/adguard-filters-list.png"})),(0,r.yg)("h4",{id:"options-46"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your AdGuard Home instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your username here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your password here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showOnOffStatusOnly"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),", will only show aggregated AdGuard filter status (on/off), instead of a list of filters")))),(0,r.yg)("h4",{id:"example-43"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: adguard-filter-status\n useProxy: true\n options:\n hostname: http://127.0.0.1\n username: admin\n password: test\n showOnOffStatusOnly: false\n")),(0,r.yg)("h4",{id:"info-45"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://adguard.com/en/privacy.html"},"AdGuard Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adguard-home-dns-info"},"AdGuard Home DNS Info"),(0,r.yg)("p",null,"Fetches data from your ",(0,r.yg)("a",{parentName:"p",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home")," instance, and displays the current status (Enabled / Disabled) of AdGuard DNS. Click show more to view detailed info, including upstream DNS provider, active ports, and the status of DNSSEC, EDNS CS, PTR and IPv6."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/G0JngBb/adguard-dns-info.png"})),(0,r.yg)("h4",{id:"options-47"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your AdGuard Home instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your username here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your password here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showFullInfo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If set to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"),', the full DNS info will be shown by default, without having to click "Show Info"')))),(0,r.yg)("h4",{id:"example-44"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: adguard-dns-info\n useProxy: true\n options:\n hostname: http://127.0.0.1\n username: admin\n password: test\n showFullInfo: false\n")),(0,r.yg)("h4",{id:"info-46"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://adguard.com/en/privacy.html"},"AdGuard Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adguard-home-top-domains"},"AdGuard Home Top Domains"),(0,r.yg)("p",null,"Fetches data from your ",(0,r.yg)("a",{parentName:"p",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home")," instance, and displays a list of the most queried, and most blocked domains."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"600",src:"https://i.ibb.co/qRhYYTk/adguard-top-domains.png"})),(0,r.yg)("h4",{id:"options-48"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to your AdGuard Home instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your username here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you've got auth enabled on AdGuard, provide your password here")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify the number of results to show, between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"100"),", defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"10"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideBlockedDomains"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Don't show the blocked domains list (queried domains only)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideQueriedDomains"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Don't show the queried domains list (blocked domains only)")))),(0,r.yg)("h4",{id:"example-45"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: adguard-top-domains\n useProxy: true\n options:\n hostname: http://127.0.0.1\n username: admin\n password: test\n limit: 10\n")),(0,r.yg)("h4",{id:"info-47"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://adguard.com/en/adguard-home/overview.html"},"AdGuard Home"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://adguard.com/en/privacy.html"},"AdGuard Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-user"},"Nextcloud User"),(0,r.yg)("p",null,"Nextcloud is a ",(0,r.yg)("a",{parentName:"p",href:"https://nextcloud.com/install/#instructions-server"},"self hosted")," productivity platform, it can also be used free of charge with ",(0,r.yg)("a",{parentName:"p",href:"https://nextcloud.com/sign-up/"},"hundreds of existing hosting providers")," that offer a free Nextcloud account."),(0,r.yg)("p",null,"Displays branding information of a Nextcloud server (logo, url, slogan) and some user details (name, login name, last login, disk space or quota). Use with regular or admin user."),(0,r.yg)("p",null,"Shows quota usage when quota is enabled for the user or disk usage when not enabled."),(0,r.yg)("p",null,"Known issues: the User API incorrectly reports available disk space as total for admin users when quota is not enabled (which usually is the case for admins)."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/F8Fdm3t/nextcloud-user.png",alt:"nextcloud-user"})),(0,r.yg)("h4",{id:"options-49"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud username")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")))),(0,r.yg)("h4",{id:"example-46"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-user\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n")),(0,r.yg)("h4",{id:"info-48"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-user-statuses"},"Nextcloud User Statuses"),(0,r.yg)("p",null,"Show user statuses for selected users."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/Lk4DFT5/nextcloud-userstatus.png",alt:"nextcloud-userstatus"})),(0,r.yg)("h4",{id:"options-50"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud username")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"users"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"array")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud User IDs to show statuses for, list size between ",(0,r.yg)("inlineCode",{parentName:"td"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"100"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"showEmpty"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Show statuses without a message, defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"true"))))),(0,r.yg)("h4",{id:"example-47"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-userstatus\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n users: ['bob', 'alice']\n")),(0,r.yg)("h4",{id:"info-49"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-notifications"},"Nextcloud Notifications"),(0,r.yg)("p",null,"Displays your notifications and allows deleting them."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/yQCS51k/nextcloud-notifications.png",alt:"nextcloud-notifications"})),(0,r.yg)("h4",{id:"options-51"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud username")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number\\|string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit displayed notifications either by count, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"5")," to show the 5 most recent, or by age, e.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"1d")," to only show notifications not older than a day. Accepted suffixes for age limit are ",(0,r.yg)("inlineCode",{parentName:"td"},"m"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"h")," and ",(0,r.yg)("inlineCode",{parentName:"td"},"d"),".")))),(0,r.yg)("h4",{id:"example-48"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-notifications\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n limit: 6h\n")),(0,r.yg)("h4",{id:"info-50"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-system"},"Nextcloud System"),(0,r.yg)("p",null,"Visualises overall memory utilisation and CPU load averages, shows server versions."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/KW4t6nG/nextcloud-system.png",alt:"nextcloud-system"})),(0,r.yg)("h4",{id:"options-52"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Must be a Nextcloud admin user")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")))),(0,r.yg)("h4",{id:"example-49"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-system\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n")),(0,r.yg)("h4",{id:"info-51"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-stats"},"Nextcloud Stats"),(0,r.yg)("p",null,"Shows key usage statistics about your Nextcloud server."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/pPXPQFB/nextcloud-stats.png",alt:"nextcloud-stats"})),(0,r.yg)("h4",{id:"options-53"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Must be a Nextcloud admin user")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")))),(0,r.yg)("h4",{id:"example-50"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-stats\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n")),(0,r.yg)("h4",{id:"info-52"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"nextcloud-php-opcache-stats"},"Nextcloud PHP OPcache Stats"),(0,r.yg)("p",null,"Shows statistics about PHP OPcache performance on your Nextcloud server."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/xf6M4J2/nextcloud-phpopcache.png",alt:"nextcloud-phpopcache"})),(0,r.yg)("h4",{id:"options-54"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Nextcloud server")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Must be a Nextcloud admin user")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"Nextcloud app-password (create one in Settings -> Security)")))),(0,r.yg)("h4",{id:"example-51"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: nextcloud-php-opcache\n useProxy: true\n options:\n hostname: https://nextcloud.example.com\n username: alice\n password: xxxxx-xxxxx-xxxxx-xxxxx\n")),(0,r.yg)("h4",{id:"info-53"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://nextcloud.com"},"Nextcloud"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://nextcloud.com/privacy"},"Nextcloud Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"proxmox-lists"},"Proxmox lists"),(0,r.yg)("p",null,"Shows lists of nodes, containers, and VMs in a Proxmox virtual environment cluster, with a status indicator."),(0,r.yg)("h4",{id:"options-55"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"cluster_url"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the proxmox cluster server. No trailing ",(0,r.yg)("inlineCode",{parentName:"td"},"/"),". for example: ",(0,r.yg)("inlineCode",{parentName:"td"},"https://proxmox.lan:8006"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"user_name"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A Proxmox API Username, for example ",(0,r.yg)("inlineCode",{parentName:"td"},"root@pam")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"dashy@pve"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"token_name"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A Proxmox API token name. You can get a token in the API section of the cluster management interface.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"token_uuid"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The value of the token entered above. This is normally a UUID.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"node"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"A Proxmox node name. If empty or not supplied, a list of nodes will be shown.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"node_data"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"This is required if a node is selected, Currently this accepts two values, either ",(0,r.yg)("inlineCode",{parentName:"td"},"lxc")," or ",(0,r.yg)("inlineCode",{parentName:"td"},"qemu")," but the widget can be improved to get other types of data from the Proxmox API.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"A widget title.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"title_as_link"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"When this is set to anything other than 0 or false, the title will be linked to the value entered in the ",(0,r.yg)("inlineCode",{parentName:"td"},"cluster_url")," option.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"footer"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"A widget footer.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"footer_as_link"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"When this is set to anything other than 0 or false, the title will be linked to the value entered in the ",(0,r.yg)("inlineCode",{parentName:"td"},"cluster_url")," option.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hide_templates"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},"optional"),(0,r.yg)("td",{parentName:"tr",align:null},"When this is set to anything other than 0 or false, templates will be filtered out of the result list.")))),(0,r.yg)("h4",{id:"example-52"},"Example"),(0,r.yg)("p",null,"This will show the list of nodes."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: proxmox-lists\n useProxy: true \n options:\n cluster_url: https://proxmox.lan:8006\n user_name: root@pam\n token_name: dashy\n token_uuid: bfb152df-abcd-abcd-abcd-ccb95a472d01\n")),(0,r.yg)("p",null,"This will show the list of VMs, with a title and a linked fotter, hiding VM templates."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: proxmox-lists\n useProxy: true \n options:\n cluster_url: https://proxmox.lan:8006\n user_name: root@pam\n token_name: dashy\n token_uuid: bfb152df-abcd-abcd-abcd-ccb95a472d01\n node: proxmox\n node_data: qemu\n title: Proxmox VMs\n title_as_link: false\n footer: Proxmox\n footer_as_link: true\n hide_templates: 1\n")),(0,r.yg)("h4",{id:"info-54"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://proxmox.com/en/proxmox-ve"},"Proxmox Virtual Environment"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://proxmox.com/en/privacy-policy"},"Proxmox's Privacy Policy")))),(0,r.yg)("h4",{id:"troubleshooting"},"Troubleshooting"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"404 Error in development mode"),": The error might disappear in production mode ",(0,r.yg)("inlineCode",{parentName:"li"},"yarn start")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"500 Error in production mode"),": Try adding the certificate authority (CA) certificate of your Proxmox host to Node.js. ",(0,r.yg)("ul",{parentName:"li"},(0,r.yg)("li",{parentName:"ul"},"Download the Proxmox CA certificate to your Dashy host."),(0,r.yg)("li",{parentName:"ul"},"Export environment variable ",(0,r.yg)("inlineCode",{parentName:"li"},"NODE_EXTRA_CA_CERTS")," and set its value to the path of the downloaded CA certificate. Example: ",(0,r.yg)("inlineCode",{parentName:"li"},"export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/devlab_ca.pem"))))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"sabnzbd"},"Sabnzbd"),(0,r.yg)("p",null,"Shows queue information regarding your self hosted Sabnzbd server."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"450",src:"https://i.ibb.co/5TTSRyM/sabnzbd.png",alt:"Sabnzbd"})),(0,r.yg)("h4",{id:"options-56"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"sabnzbdUrl"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Sabnzbd server. No trailing ",(0,r.yg)("inlineCode",{parentName:"td"},"/"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"API key for Sabnzbd access. Located under ",(0,r.yg)("inlineCode",{parentName:"td"},"Config")," -> ",(0,r.yg)("inlineCode",{parentName:"td"},"General")," -> ",(0,r.yg)("inlineCode",{parentName:"td"},"Security")," -> ",(0,r.yg)("inlineCode",{parentName:"td"},"API Key"),".")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideDetails"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Hides extra server queue details.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hideQueue"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"boolean")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Hides the queue list in an expandable dropdown.")))),(0,r.yg)("h4",{id:"example-53"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"}," - type: sabnzbd\n options:\n sabnzbdUrl: 'https://sabnzbd.example.com'\n apiKey: XXXXXXXXXXXXXXXXXX\n hideDetails: false\n hideQueue: false\n")),(0,r.yg)("h4",{id:"info-55"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://sabnzbd.org/"},"Sabnzbd"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://forums.sabnzbd.org/ucp.php?mode=privacy"},"Sabnzbd Privacy Policy")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"gluetun-vpn-info"},"Gluetun VPN Info"),(0,r.yg)("p",null,"Display info from the Gluetun VPN container public IP API. This can show the IP and location data for the exit VPN node."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/xjXbZ7Z/Screenshot-from-2022-07-20-21-42-34.png"})),(0,r.yg)("h4",{id:"options-57"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"visibleFields"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"A comma separated list of the fields you want visible in the widget. You can have any number of the following : ",(0,r.yg)("inlineCode",{parentName:"td"},"public_ip"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"region"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"country"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"city"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"location"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"organisation"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"postal_code"),", ",(0,r.yg)("inlineCode",{parentName:"td"},"timezone"),". Defaults to just ",(0,r.yg)("inlineCode",{parentName:"td"},"public_ip"))),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The url to the gluetun HTTP control server. E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"http://gluetun:8000"))))),(0,r.yg)("h4",{id:"example-54"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gluetun-status\n useProxy: true\n options:\n hostname: http://server-or-conatiner-hostname:8000\n visibleFields: public_ip,region,country,city,location,organisation,postal_code,timezone\n")),(0,r.yg)("h4",{id:"info-56"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe0 Proxied"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/qdm12/gluetun"},"Gluetun"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://github.com/qdm12/gluetun/wiki"},"Gluetun Wiki")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"drone-ci-builds"},"Drone CI Builds"),(0,r.yg)("p",null,"Display the last builds from a ",(0,r.yg)("a",{parentName:"p",href:"https://www.drone.ci"},"Drone CI")," instance. A self-hosted CI system that uses docker."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"380",src:"https://i.ibb.co/nQM3BXj/Bildschirm-foto-2023-01-07-um-01-31-45.png"})),(0,r.yg)("h4",{id:"options-58"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The hostname of the Drone CI instance.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The API key (https://","[your-drone-instance]","/account).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"integer")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the amounts of listed builds.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"repo"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Show only builds of the specified repo")))),(0,r.yg)("h4",{id:"example-55"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: drone-io\n updateInterval: 30\n options:\n host: https://drone.somedomain.com\n apiKey: my-very-secret-api-key\n limit: 10\n")),(0,r.yg)("h4",{id:"info-57"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://www.drone.io"},"Drone"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://www.drone.io"},"Drone")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"linkding"},"Linkding"),(0,r.yg)("p",null,"Linkding is a self-hosted bookmarking service, which has a clean interface and is simple to set up. This lists the links, filterable by tags."),(0,r.yg)("h4",{id:"options-59"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"host"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The hostname of the Drone CI instance.")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The API key (https://your-linkding-instance/settings/integrations).")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"tags"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"list of string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Filter the links by tag.")))),(0,r.yg)("h4",{id:"example-56"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: linkding\n updateInterval: 30\n options:\n host: https://lingding.somedomain.com\n apiKey: my-very-secret-api-key\n tags: \n - rpg\n - markdown\n")),(0,r.yg)("h4",{id:"info-58"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sissbruecker/linkding"},"Linkding"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://github.com/sissbruecker/linkding"},"Linkding")))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"uptime-kuma"},"Uptime Kuma"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://github.com/louislam/uptime-kuma"},"Uptime Kuma")," is an easy-to-use self-hosted monitoring tool."),(0,r.yg)("h4",{id:"options-60"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"url"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL of the Uptime Kuma instance")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiKey"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The API key (see ",(0,r.yg)("a",{parentName:"td",href:"https://github.com/louislam/uptime-kuma/wiki/API-Keys"},"https://github.com/louislam/uptime-kuma/wiki/API-Keys"),").")))),(0,r.yg)("h4",{id:"example-57"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: uptime-kuma\n useProxy: true\n options:\n apiKey: uk2_99H0Yd3I2pPNIRfn0TqBFu4g5q85R1Mh75yZzw6H\n url: http://192.168.1.106:3691/metrics\n")),(0,r.yg)("h4",{id:"info-59"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe2 Required"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/louislam/uptime-kuma"},"Uptime Kuma")," )"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": ",(0,r.yg)("em",{parentName:"li"},"See ",(0,r.yg)("a",{parentName:"em",href:"https://github.com/louislam/uptime-kuma"},"Uptime Kuma")))),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"system-resource-monitoring"},"System Resource Monitoring"),(0,r.yg)("h3",{id:"glances"},"Glances"),(0,r.yg)("p",null,"The easiest method for displaying system info and resource usage in Dashy is with ",(0,r.yg)("a",{parentName:"p",href:"https://nicolargo.github.io/glances/"},"Glances"),"."),(0,r.yg)("p",null,"Glances is a cross-platform monitoring tool developed by ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/nicolargo"},"@nicolargo"),". It's similar to top/htop but with a ",(0,r.yg)("a",{parentName:"p",href:"https://glances.readthedocs.io/en/latest/api.html"},"Rest API")," and many ",(0,r.yg)("a",{parentName:"p",href:"https://glances.readthedocs.io/en/latest/gw/index.html"},"data exporters")," available. Under the hood, it uses ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/giampaolo/psutil"},"psutil")," for retrieving system info."),(0,r.yg)("p",null,"If you don't already have it installed, either follow the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/nicolargo/glances/blob/master/README.rst"},"Installation Guide")," for your system, or setup ",(0,r.yg)("a",{parentName:"p",href:"https://glances.readthedocs.io/en/latest/docker.html"},"with Docker"),", or use the one-line install script: ",(0,r.yg)("inlineCode",{parentName:"p"},"curl -L https://bit.ly/glances | /bin/bash"),"."),(0,r.yg)("p",null,"If you are using Docker to run glances make sure to add the enviroment variable ",(0,r.yg)("inlineCode",{parentName:"p"},"-e TZ = {YourTimeZone}"),". You can get a list of valid timezones by running ",(0,r.yg)("inlineCode",{parentName:"p"},"timedatectl list-timezones")," on any linux system. This is needed so the graphs show the currect time."),(0,r.yg)("p",null,"Here an example for Docker"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," docker run -d \\\n --name glances \\\n --restart unless-stopped \\\n -v /var/run/docker.sock:/var/run/docker.sock:ro \\\n -p 61208:61208 \\\n --pid host \\\n --privileged \\\n -e GLANCES_OPT=-w \\\n -e PUID=1000 \\\n -e PGID=1000 \\\n -e TZ=Europe/Zurich \\\n nicolargo/glances:latest\n")),(0,r.yg)("p",null,"Glances can be launched with the ",(0,r.yg)("inlineCode",{parentName:"p"},"glances")," command. You'll need to run it in web server mode, using the ",(0,r.yg)("inlineCode",{parentName:"p"},"-w")," option for the API to be reachable. If you don't plan on using the Web UI, then you can disable it using ",(0,r.yg)("inlineCode",{parentName:"p"},"--disable-webui"),". See the ",(0,r.yg)("a",{parentName:"p",href:"https://glances.readthedocs.io/en/latest/cmds.html"},"command reference docs")," for more info."),(0,r.yg)("p",null,"If Glaces is running on a Windows system it is recommanded to add the following arguments ",(0,r.yg)("inlineCode",{parentName:"p"},"--disable-plugin all --enable-plugin cpu,mem,diskio,ip,network,containers,quicklook,load,fs,alert -w")," This is due to Glances not being that stable on windows, so disabling all plugins that aren't used by Dashy widgets can save on ressources."),(0,r.yg)("h4",{id:"options-61"},"Options"),(0,r.yg)("p",null,"All Glance's based widgets require a ",(0,r.yg)("inlineCode",{parentName:"p"},"hostname"),". All other parameters are optional."),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"hostname"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL or IP + port to your Glances instance (without a trailing slash)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"username"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you have setup basic auth on Glances, specify username here (defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"glances"),")")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"password"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If you have setup basic auth on Glances, specify password here. ",(0,r.yg)("strong",{parentName:"td"},"Note"),": since this password is in plaintext, it is important not to reuse it anywhere else")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"apiVersion"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Specify an API version, defaults to V ",(0,r.yg)("inlineCode",{parentName:"td"},"3"),". Note that support for older versions is limited")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"For widgets that show a time-series chart, optionally limit the number of data points returned. A higher number will show more historical results, but will take longer to load. A value between 300 - 800 is usually optimal")))),(0,r.yg)("p",null,"Note that if auth is configured, requests must be proxied with ",(0,r.yg)("inlineCode",{parentName:"p"},"useProxy: true")),(0,r.yg)("h4",{id:"info-60"},"Info"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"CORS"),": \ud83d\udfe2 Enabled"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Auth"),": \ud83d\udfe0 Optional"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Price"),": \ud83d\udfe2 Free"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Host"),": Self-Hosted (see ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/nicolargo/glances"},"GitHub - Nicolargo/Glances"),")"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("strong",{parentName:"li"},"Privacy"),": \u26ab No Policy Available")),(0,r.yg)("h4",{id:"screenshot"},"Screenshot"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://ibb.co/pR6dMZT"},(0,r.yg)("img",{parentName:"a",src:"https://i.ibb.co/xfK6BGb/system-monitor-board.png",alt:"example-screenshot"}))),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"current-cpu-usage"},"Current CPU Usage"),(0,r.yg)("p",null,"Live-updating current CPU usage, as a combined average across all cores"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/qkLgxLp/gl-cpu-usage.png"})),(0,r.yg)("h4",{id:"example-58"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-current-cpu\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"current-cpu-usage-speedometer"},"Current CPU Usage Speedometer"),(0,r.yg)("p",null,"Speedometer styled version of the Current CPU Usage widget"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/7RHTRNq/gl-cpu-speedometer.png"})),(0,r.yg)("h4",{id:"example-59"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-cpu-speedometer\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cpu-usage-per-core"},"CPU Usage Per Core"),(0,r.yg)("p",null,"Live-updating CPU usage breakdown per core"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/512MYhT/gl-cpu-cores.png"})),(0,r.yg)("h4",{id:"example-60"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-current-cores\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cpu-usage-history"},"CPU Usage History"),(0,r.yg)("p",null,"Recent CPU usage history, across all cores, and displayed by user and system"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/zs8BDzR/gl-cpu-history.png"})),(0,r.yg)("h4",{id:"options-62"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of results returned, rendering more data points will take longer to load. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"100"))))),(0,r.yg)("h4",{id:"example-61"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-cpu-history\n options:\n hostname: http://192.168.130.2:61208\n limit: 60\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"current-memory-usage"},"Current Memory Usage"),(0,r.yg)("p",null,"Real-time memory usage gauge, with more info visible on click"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/rynp52J/gl-mem-usage.png"})),(0,r.yg)("h4",{id:"example-62"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-current-mem\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"current-memory-usage-speedometer"},"Current Memory Usage Speedometer"),(0,r.yg)("p",null,"Speedometer styled version of the Current Memory Usage widget"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/wsNW7Xr/gl-mem-speedometer.png"})),(0,r.yg)("h4",{id:"example-63"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-mem-speedometer\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"memory-usage-history"},"Memory Usage History"),(0,r.yg)("p",null,"Recent memory usage chart"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/V3wSgW0/gl-mem-history.png"})),(0,r.yg)("h4",{id:"options-63"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"limit"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Limit the number of results returned, rendering more data points will take longer to load. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"100"))))),(0,r.yg)("h4",{id:"example-64"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-mem-history\n options:\n hostname: http://localhost:61208\n limit: 80\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"disk-space"},"Disk Space"),(0,r.yg)("p",null,"List connected disks, showing free / used space and other info (file system, mount point and space available)"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/25y94bB/gl-disk-usage.png"})),(0,r.yg)("h4",{id:"example-65"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-disk-space\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"disk-io"},"Disk IO"),(0,r.yg)("p",null,"Shows real-time read and write speeds and operations per sec for each disk"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/JdgjCjG/gl-disk-io.png"})),(0,r.yg)("h4",{id:"example-66"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-disk-io\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"system-load"},"System Load"),(0,r.yg)("p",null,"Shows the number of processes waiting in the run-queue, averaged across all cores. Displays for past 5, 10 and 15 minutes"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/090FfNy/gl-system-load.png"})),(0,r.yg)("h4",{id:"example-67"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-system-load\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"system-load-history"},"System Load History"),(0,r.yg)("p",null,"Shows recent historical system load, calculated from the number of processes waiting in the run-queue, in 1, 5 and 15 minute intervals, and averaged across all cores. Optionally specify ",(0,r.yg)("inlineCode",{parentName:"p"},"limit")," to set number of results returned, defaults to ",(0,r.yg)("inlineCode",{parentName:"p"},"500"),", max ",(0,r.yg)("inlineCode",{parentName:"p"},"100000"),", but the higher the number the longer the load and render times will be."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"500",src:"https://i.ibb.co/C2rGMLg/system-load-history.png"})),(0,r.yg)("h4",{id:"example-68"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-load-history\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"network-interfaces"},"Network Interfaces"),(0,r.yg)("p",null,"Lists visible network interfaces, including real-time upload/ download stats"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/FnhgHfG/gl-network-interfaces.png"})),(0,r.yg)("h4",{id:"example-69"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-network-interfaces\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"network-traffic"},"Network Traffic"),(0,r.yg)("p",null,"Shows amount of data recently uploaded/ downloaded across all network interfaces. Optionally set the ",(0,r.yg)("inlineCode",{parentName:"p"},"limit")," option to specify number historical of data points to return"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/12RN6KT/gl-network-traffic.png"})),(0,r.yg)("h4",{id:"example-70"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-network-traffic\n options:\n hostname: http://192.168.130.2:61208\n limit: 500\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"resource-usage-alerts"},"Resource Usage Alerts"),(0,r.yg)("p",null,"Lists recent high resource usage alerts (e.g. CPU, mem, IO, load, temp)"),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/w01NX5R/gl-alerts.png"})),(0,r.yg)("h4",{id:"example-71"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-alerts\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"ip-address"},"IP Address"),(0,r.yg)("p",null,"Shows public and private IP address. Note that the ip plugin is not available on all instances of Glances."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/ZhXBxZr/gl-ip-address.png"})),(0,r.yg)("h4",{id:"example-72"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-ip-address\n options:\n hostname: http://192.168.130.2:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"cpu-temp"},"CPU Temp"),(0,r.yg)("p",null,"Displays temperature data from system CPUs."),(0,r.yg)("p",null,"Note: This widget uses the ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/nicolargo/glances/blob/develop/glances/plugins/glances_sensors.py"},(0,r.yg)("inlineCode",{parentName:"a"},"sensors"))," plugin, which is disabled by default, and may cause ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/nicolargo/glances/issues/1664#issuecomment-632063558"},"performance issues"),".\nYou'll need to enable the sensors plugin to use this widget, using: ",(0,r.yg)("inlineCode",{parentName:"p"},"--enable-plugin sensors")," when you start Glances."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/xSs4Gqd/gl-cpu-temp.png"})),(0,r.yg)("h4",{id:"options-64"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"units"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Use ",(0,r.yg)("inlineCode",{parentName:"td"},"C")," to display temperatures in Celsius or ",(0,r.yg)("inlineCode",{parentName:"td"},"F")," to use Fahrenheit. Defaults to ",(0,r.yg)("inlineCode",{parentName:"td"},"C"),".")))),(0,r.yg)("h4",{id:"example-73"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-cpu-temp\n options:\n hostname: http://192.168.130.2:61208\n units: C\n")),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"dynamic-widgets"},"Dynamic Widgets"),(0,r.yg)("h3",{id:"iframe-widget"},"Iframe Widget"),(0,r.yg)("p",null,"Embed any webpage into your dashboard as a widget."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/t4VHnh3/iframe-widget.gif"})),(0,r.yg)("h4",{id:"options-65"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"url"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},"Required"),(0,r.yg)("td",{parentName:"tr",align:null},"The URL to the webpage to embed")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"frameHeight"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"number")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"If needed, specify height of iframe in ",(0,r.yg)("inlineCode",{parentName:"td"},"px"),". E.g. ",(0,r.yg)("inlineCode",{parentName:"td"},"400"),", defaults to auto")))),(0,r.yg)("h4",{id:"example-74"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: iframe\n options:\n url: https://fiatleak.com/\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"html-embedded-widget"},"HTML Embedded Widget"),(0,r.yg)("p",null,"Many websites and apps provide their own embeddable widgets. These can be used with Dashy using the Embed widget, which lets you dynamically embed and HTML, CSS or JavaScript contents."),(0,r.yg)("p",null,"\u26a0\ufe0f ",(0,r.yg)("strong",{parentName:"p"},"NOTE:")," Use with extreme caution. Embedding a script from an untrustworthy source may have serious unintended consequences."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"400",src:"https://i.ibb.co/fkwNnxT/embed-widget-2.png"})),(0,r.yg)("h4",{id:"options-66"},"Options"),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Field")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Type")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Required")),(0,r.yg)("th",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"th"},"Description")))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"html"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"HTML contents to render in the widget")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"script"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Raw JavaScript code to execute (caution)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"scriptSrc"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"A URL to JavaScript content (caution)")),(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("strong",{parentName:"td"},(0,r.yg)("inlineCode",{parentName:"strong"},"css"))),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("inlineCode",{parentName:"td"},"string")),(0,r.yg)("td",{parentName:"tr",align:null},(0,r.yg)("em",{parentName:"td"},"Optional")),(0,r.yg)("td",{parentName:"tr",align:null},"Any stylings for widget contents")))),(0,r.yg)("h4",{id:"example-75"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},'- type: embed\n options:\n scriptSrc: https://cdn.speedcheck.org/basic/scbjs.min.js\n html: |\n
\n
\n \n Speedcheck\n \n
\n
\n')),(0,r.yg)("p",null,"Or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},'- type: embed\n options:\n css: \'.coinmarketcap-currency-widget { color: var(--widget-text-color); }\'\n html: \'
\'\n scriptSrc: \'https://files.coinmarketcap.com/static/widget/currency.js\'\n')),(0,r.yg)("p",null,"You can also use this widget to display an image, wither locally or from a remote origin."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: embed\n options:\n html: ''\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"api-response"},"API Response"),(0,r.yg)("p",null,"Directly output plain-text response from any API-enabled service."),(0,r.yg)("p",null,"// Coming soon..."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"prometheus-data"},"Prometheus Data"),(0,r.yg)("p",null,"Display data from any service with a Prometheus exporter."),(0,r.yg)("p",null,"// Coming soon..."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"data-feed"},"Data Feed"),(0,r.yg)("p",null,"Show live data from an RSS-enabled service. The only required parameter is ",(0,r.yg)("inlineCode",{parentName:"p"},"rssUrl"),", which is the URL to the ATOM feed. See ",(0,r.yg)("a",{parentName:"p",href:"#rss-feed"},"RSS Widget")," for full list of available options."),(0,r.yg)("p",{align:"center"},(0,r.yg)("img",{width:"700",src:"https://i.ibb.co/1r88pvL/rss-feed-example-1.png"})),(0,r.yg)("h4",{id:"example-76"},"Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: rss-feed\n options:\n rssUrl: https://notes.aliciasykes.com/feed\n")),(0,r.yg)("hr",null),(0,r.yg)("h2",{id:"usage--customizations"},"Usage & Customizations"),(0,r.yg)("h3",{id:"widget-usage-guide"},"Widget Usage Guide"),(0,r.yg)("p",null,"Like items, widgets are placed under sections. You may have one or more widgets per section."),(0,r.yg)("p",null,"In your YAML config file, this will look something like:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"sections:\n- name: Today\n icon: far fa-calendar-day\n widgets:\n - type: clock\n options:\n format: en-GB\n - type: weather\n options:\n apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n city: London\n units: metric\n")),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},'In this example, there is a single section, named "Today", using a Calendar icon from Font-Awesome. It has 2 widgets, a clock and the current weather.')),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"continuous-updates"},"Continuous Updates"),(0,r.yg)("p",null,"By default, a widget which displays dynamic data from an external source, will only fetch results on page load. If you would like to keep data updated at all times, you can enable ",(0,r.yg)("strong",{parentName:"p"},"Continuous Updates"),". This is done by setting a time value in the ",(0,r.yg)("inlineCode",{parentName:"p"},"updateInterval")," field."),(0,r.yg)("p",null,"The value of ",(0,r.yg)("inlineCode",{parentName:"p"},"updateInterval")," is optional, and is specified and seconds. It must be more than ",(0,r.yg)("inlineCode",{parentName:"p"},"10")," and less than ",(0,r.yg)("inlineCode",{parentName:"p"},"7200"),"."),(0,r.yg)("p",null,"For example, the following widget displaying stats from Pi-Hole will update ever 20 seconds."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"widgets:\n- type: pi-hole-stats\n updateInterval: 20\n options:\n hostname: http://192.168.130.2\n")),(0,r.yg)("p",null,"Note that if you have many widgets, and set them to continuously update frequently, you will notice a hit to performance. A widget that relies on data from an external API, will also consume your usage quota faster, if set to keep updating."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"proxying-requests"},"Proxying Requests"),(0,r.yg)("p",null,"If a widget fails to make a data request, and the console shows a CORS error, this means the server is blocking client-side requests."),(0,r.yg)("p",null,"Dashy has a built-in CORS proxy (",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/blob/master/services/cors-proxy.js"},(0,r.yg)("inlineCode",{parentName:"a"},"services/cors-proxy.js")),"), which will be used automatically by some widgets, or can be forced to use by other by setting the ",(0,r.yg)("inlineCode",{parentName:"p"},"useProxy")," option."),(0,r.yg)("p",null,"For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"widgets:\n- type: pi-hole-stats\n useProxy: true\n options:\n hostname: http://pi-hole.local\n")),(0,r.yg)("p",null,"Alternatively, and more securely, you can set the auth headers on your service to accept requests from Dashy. For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"Access-Control-Allow-Origin: https://location-of-dashy/\nVary: Origin\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"setting-timeout"},"Setting Timeout"),(0,r.yg)("p",null,"If the endpoint you are requesting data from is slow to respond, you may see a timeout error in the console. This can easily be fixed by specifying the ",(0,r.yg)("inlineCode",{parentName:"p"},"timeout")," property on the offending widget. This should be an integer value, in milliseconds. By default timeout is ",(0,r.yg)("inlineCode",{parentName:"p"},"2500")," ms (2\xbd seconds)."),(0,r.yg)("p",null,"For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-current-cpu\n timeout: 8000\n options:\n hostname: https://glances.dns-device.local\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"adding-labels"},"Adding Labels"),(0,r.yg)("p",null,"If you have multiple widgets of the same type in a single section, it may not be clear what each one is. To overcome this, you can add a custom label to any given widget, using the ",(0,r.yg)("inlineCode",{parentName:"p"},"label")," property."),(0,r.yg)("p",null,"For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- name: CPU Usage\n icon: fas fa-tachometer\n widgets:\n - type: gl-current-cpu\n label: Meida Server\n options:\n hostname: http://media-server.lan:61208\n - type: gl-current-cpu\n label: Firewall\n options:\n hostname: http://firewall.lan:61208\n - type: gl-current-cpu\n label: File Sync Server\n options:\n hostname: http://file-sync.lan:61208\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"ignoring-errors"},"Ignoring Errors"),(0,r.yg)("p",null,"When there's an error fetching or displaying a widgets data, then it will be highlighted in yellow, and a message displayed on the UI."),(0,r.yg)("p",null,"In some instances, this is a false positive, and the widget is actually functioning correctly. If this is the case, you can disable the UI error message of a given widget by setting: ",(0,r.yg)("inlineCode",{parentName:"p"},"ignoreErrors: true")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-disk-io\n ignoreErrors: true\n options:\n hostname: https://glances.dns-device.local\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"widget-styling"},"Widget Styling"),(0,r.yg)("p",null,"Like elsewhere in Dashy, all colours can be easily modified with CSS variables."),(0,r.yg)("p",null,"Widgets use the following color variables, which can be overridden if desired:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"--widget-text-color")," - Text color, defaults to ",(0,r.yg)("inlineCode",{parentName:"li"},"--primary")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"--widget-background-color")," - Background color, defaults to ",(0,r.yg)("inlineCode",{parentName:"li"},"--background-darker")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"--widget-accent-color")," - Accent color, defaults to ",(0,r.yg)("inlineCode",{parentName:"li"},"--background"))),(0,r.yg)("p",null,"For more info on how to apply custom variables, see the ",(0,r.yg)("a",{parentName:"p",href:"/docs/theming#setting-custom-css-in-the-ui"},"Theming Docs")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"customizing-charts"},"Customizing Charts"),(0,r.yg)("p",null,"For widgets that contain charts, you can set an array of colors under ",(0,r.yg)("inlineCode",{parentName:"p"},"chartColors"),".\nTo specify the chart height, set ",(0,r.yg)("inlineCode",{parentName:"p"},"chartHeight")," to an integer (in ",(0,r.yg)("inlineCode",{parentName:"p"},"px"),"), defaults to ",(0,r.yg)("inlineCode",{parentName:"p"},"300"),".\nFor example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-yaml"},"- type: gl-load-history\n options:\n hostname: http://192.168.130.2:61208\n chartColors: ['#9b5de5', '#f15bb5', '#00bbf9', '#00f5d4']\n chartHeight: 450\n")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"language-translations"},"Language Translations"),(0,r.yg)("p",null,"Since most of the content displayed within widgets is fetched from an external API, unless that API supports multiple languages, translating dynamic content is not possible."),(0,r.yg)("p",null,"However, any hard-coded content is translatable, and all dates and times will display in your local format."),(0,r.yg)("p",null,"For more info about multi-language support, see the ",(0,r.yg)("a",{parentName:"p",href:"/docs/multi-language-support"},"Internationalization Docs"),"."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"widget-ui-options"},"Widget UI Options"),(0,r.yg)("p",null,"Widgets can be opened in full-page view, by clicking the Arrow icon (top-right). The URL in your address bar will also update, and visiting that web address directly will take you straight to that widget."),(0,r.yg)("p",null,"You can reload the data of any widget, by clicking the Refresh Data icon (also in top-right). This will only affect the widget where the action was triggered from."),(0,r.yg)("p",null,"All ",(0,r.yg)("a",{parentName:"p",href:"/docs/configuring#section"},"config options")," that can be applied to sections, can also be applied to widget sections. For example, to make a widget section double the width, set ",(0,r.yg)("inlineCode",{parentName:"p"},"displayData.cols: 2")," within the parent section. You can collapse a widget (by clicking the section title), and collapse state will be saved locally."),(0,r.yg)("p",null,"Widgets cannot currently be edited through the UI. This feature is in development, and will be released soon. In the meantime, you can either use the JSON config editor, or use ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/coder/code-server"},"VS Code Server"),", or just SSH into your box and edit the conf.yml file directly."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"build-your-own-widget"},"Build your own Widget"),(0,r.yg)("p",null,"Widgets are built in a modular fashion, making it easy for anyone to create their own custom components."),(0,r.yg)("p",null,"For a full tutorial on creating your own widget, you can follow ",(0,r.yg)("a",{parentName:"p",href:"/docs/development-guides/#building-a-widget"},"this guide"),", or take a look at ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/commit/3da76ce2999f57f76a97454c0276301e39957b8e"},"here")," for a code example."),(0,r.yg)("p",null,"Alternatively, for displaying simple data, you could also just use the either the ",(0,r.yg)("a",{parentName:"p",href:"#iframe-widget"},"iframe"),", ",(0,r.yg)("a",{parentName:"p",href:"#html-embedded-widget"},"embed"),", ",(0,r.yg)("a",{parentName:"p",href:"#data-feed"},"data feed")," or ",(0,r.yg)("a",{parentName:"p",href:"#api-response"},"API response")," widgets."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"requesting-a-widget"},"Requesting a Widget"),(0,r.yg)("p",null,"Suggestions for widget ideas are welcome. But there is no guarantee that I will build your widget idea."),(0,r.yg)("p",null,"Please only request widgets for services that:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Have a publicly accessible API"),(0,r.yg)("li",{parentName:"ul"},"Are CORS and HTTPS enabled"),(0,r.yg)("li",{parentName:"ul"},"Are free to use, or have a free plan"),(0,r.yg)("li",{parentName:"ul"},"Allow for use in their Terms of Service"),(0,r.yg)("li",{parentName:"ul"},"Would be useful for other users")),(0,r.yg)("p",null,"You can suggest a widget ",(0,r.yg)("a",{parentName:"p",href:"https://git.io/Jygo3"},"here"),", please star the repo before submitting a ticket. If you are a monthly GitHub sponsor, I will happily build out a custom widget for any service that meets the above criteria, usually within 2 weeks of initial request."),(0,r.yg)("p",null,"For services that are not officially supported, it is likely still possible to display data using either the ",(0,r.yg)("a",{parentName:"p",href:"#iframe-widget"},"iframe"),", ",(0,r.yg)("a",{parentName:"p",href:"#html-embedded-widget"},"embed")," or ",(0,r.yg)("a",{parentName:"p",href:"#api-response"},"API response")," widgets. For more advanced features, like charts and action buttons, you could also build your own widget, using ",(0,r.yg)("a",{parentName:"p",href:"/docs/development-guides/#building-a-widget"},"this tutorial"),", it's fairly straight forward, and you can use an ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/Lissy93/dashy/tree/master/src/components/Widgets"},"existing widget")," (or ",(0,r.yg)("a",{parentName:"p",href:"https://git.io/JygKI"},"this example"),") as a template."),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"troubleshooting-widget-errors"},"Troubleshooting Widget Errors"),(0,r.yg)("p",null,"If an error occurs when fetching or rendering results, you will see a short message in the UI. If that message doesn't adequately explain the problem, then you can ",(0,r.yg)("a",{parentName:"p",href:"/docs/troubleshooting#how-to-open-browser-console"},"open the browser console")," to see more details."),(0,r.yg)("p",null,"Before proceeding, ensure that if the widget requires auth your API is correct, and for custom widgets, double check that the URL and protocol is correct."),(0,r.yg)("p",null,"If you're able to, you can find more information about why the request may be failing in the Dev Tools under the Network tab, and you can ensure your endpoint is correct and working using a tool like Postman."),(0,r.yg)("h4",{id:"cors-errors"},"CORS Errors"),(0,r.yg)("p",null,"The most common issue is a CORS error. This is a browser security mechanism which prevents the client-side app (Dashy) from from accessing resources on a remote origin, without that server's explicit permission (e.g. with headers like Access-Control-Allow-Origin). See the MDN Docs for more info: ",(0,r.yg)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"Cross-Origin Resource Sharing"),"."),(0,r.yg)("p",null,"There are several ways to fix a CORS error:"),(0,r.yg)("h4",{id:"option-1---ensure-correct-protocol"},"Option 1 - Ensure Correct Protocol"),(0,r.yg)("p",null,"You will get a CORS error if you try and access a http service from a https source. So ensure that the URL you are requesting has the right protocol, and is correctly formatted."),(0,r.yg)("h4",{id:"option-2---set-headers"},"Option 2 - Set Headers"),(0,r.yg)("p",null,"If you have control over the destination (e.g. for a self-hosted service), then you can simply apply the correct headers.\nAdd the ",(0,r.yg)("inlineCode",{parentName:"p"},"Access-Control-Allow-Origin")," header, with the value of either ",(0,r.yg)("inlineCode",{parentName:"p"},"*")," to allow requests from anywhere, or more securely, the host of where Dashy is served from. For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"Access-Control-Allow-Origin: https://url-of-dashy.local\n")),(0,r.yg)("p",null,"or"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-text"},"Access-Control-Allow-Origin: *\n")),(0,r.yg)("h4",{id:"option-3---proxying-request"},"Option 3 - Proxying Request"),(0,r.yg)("p",null,"You can route requests through Dashy's built-in CORS proxy. Instructions and more details can be found ",(0,r.yg)("a",{parentName:"p",href:"#proxying-requests"},"here"),". If you don't have control over the target origin, and you are running Dashy either through Docker, with the Node server or on Netlify, then this solution will work for you."),(0,r.yg)("p",null,"Just add the ",(0,r.yg)("inlineCode",{parentName:"p"},"useProxy: true")," option to the failing widget."),(0,r.yg)("h4",{id:"option-4---use-a-plugin"},"Option 4 - Use a plugin"),(0,r.yg)("p",null,"For testing purposes, you can use an addon, which will disable the CORS checks. You can get the Allow-CORS extension for ",(0,r.yg)("a",{parentName:"p",href:"https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?hl=en-US"},"Chrome")," or ",(0,r.yg)("a",{parentName:"p",href:"https://addons.mozilla.org/en-US/firefox/addon/access-control-allow-origin/"},"Firefox"),", more details ",(0,r.yg)("a",{parentName:"p",href:"https://mybrowseraddon.com/access-control-allow-origin.html"},"here")),(0,r.yg)("hr",null),(0,r.yg)("h3",{id:"raising-an-issue"},"Raising an Issue"),(0,r.yg)("p",null,"If you need to submit a bug report for a failing widget, then please include the full console output (see ",(0,r.yg)("a",{parentName:"p",href:"/docs/troubleshooting#how-to-open-browser-console"},"how"),") as well as the relevant parts of your config file. Before sending the request, ensure you've read the docs. If you're new to GitHub, an haven't previously contributed to the project, then please fist star the repo to avoid your ticket being closed by the anti-spam bot."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.8d7eb9cd.js b/assets/js/runtime~main.ac7349e8.js similarity index 93% rename from assets/js/runtime~main.8d7eb9cd.js rename to assets/js/runtime~main.ac7349e8.js index e35f04e8..0a6149dc 100644 --- a/assets/js/runtime~main.8d7eb9cd.js +++ b/assets/js/runtime~main.ac7349e8.js @@ -1 +1 @@ -(()=>{"use strict";var e,t,r,a,f,d={},b={};function o(e){var t=b[e];if(void 0!==t)return t.exports;var r=b[e]={id:e,loaded:!1,exports:{}};return d[e].call(r.exports,r,r.exports,o),r.loaded=!0,r.exports}o.m=d,o.c=b,e=[],o.O=(t,r,a,f)=>{if(!r){var d=1/0;for(i=0;i=f)&&Object.keys(o.O).every((e=>o.O[e](r[n])))?r.splice(n--,1):(b=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[r,a,f]},o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,o.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var f=Object.create(null);o.r(f);var d={};t=t||[null,r({}),r([]),r(r)];for(var b=2&a&&e;"object"==typeof b&&!~t.indexOf(b);b=r(b))Object.getOwnPropertyNames(b).forEach((t=>d[t]=()=>e[t]));return d.default=()=>e,o.d(f,d),f},o.d=(e,t)=>{for(var r in t)o.o(t,r)&&!o.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((t,r)=>(o.f[r](e,t),t)),[])),o.u=e=>"assets/js/"+({13:"9d9f8394",61:"1f391b9e",87:"e505b3a5",134:"393be207",138:"27d9d47d",146:"2140bf91",151:"0bfe2fe2",158:"0276dc25",228:"dea0f9ea",245:"f9f76190",278:"87124b4e",306:"52e2a80b",326:"f62d4472",330:"9b4185c1",332:"044d5aa6",401:"17896441",459:"4d54d076",496:"4bdb0d83",539:"9beb87c2",546:"ccab7630",552:"9be9f402",581:"935f2afb",586:"ac5280f2",588:"a3713279",634:"c4f5d8e4",676:"f52ebc2d",695:"1f5fb0df",714:"1be78505",778:"ffd4f506",790:"1745c531",814:"72e14192",831:"625b1ed7",847:"25b7c3f2",849:"18ba09e8",903:"a63906ba",992:"68d50eef"}[e]||e)+"."+{13:"cdcd7a26",61:"6f0bef76",87:"ef765b4b",90:"fffd597a",134:"2c0ad88d",138:"f584d6da",146:"f2e2506e",151:"055a0f41",158:"31602082",228:"154146d6",245:"04df3d8f",278:"78387f6b",306:"2d1ea665",326:"2688d702",330:"76280d8c",332:"f46425ff",343:"3f40ba3c",345:"8ee5f24c",401:"2d945a38",459:"232023dd",496:"1cbee4f4",504:"1b68801e",539:"70b0135c",546:"9d741c50",552:"10e8571e",581:"f58a9a76",586:"a02d052e",588:"c25e1b3a",593:"8fb47887",634:"d5b77601",676:"6d2e7ffb",695:"24f394c3",714:"93b17e9c",778:"eb67f751",790:"44ad1d35",814:"c3b3a598",831:"57bbcc5e",847:"a717e408",849:"e467166a",896:"acea2065",903:"7c16ee9f",913:"dd95d7ef",992:"ad0d74b4"}[e]+".js",o.miniCssF=e=>"assets/css/styles.de060916.css",o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},f="dashy:",o.l=(e,t,r,d)=>{if(a[e])a[e].push(t);else{var b,n;if(void 0!==r)for(var c=document.getElementsByTagName("script"),i=0;i{b.onerror=b.onload=null,clearTimeout(l);var f=a[e];if(delete a[e],b.parentNode&&b.parentNode.removeChild(b),f&&f.forEach((e=>e(r))),t)return t(r)},l=setTimeout(u.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=u.bind(null,b.onerror),b.onload=u.bind(null,b.onload),n&&document.head.appendChild(b)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.p="/",o.gca=function(e){return e={17896441:"401","9d9f8394":"13","1f391b9e":"61",e505b3a5:"87","393be207":"134","27d9d47d":"138","2140bf91":"146","0bfe2fe2":"151","0276dc25":"158",dea0f9ea:"228",f9f76190:"245","87124b4e":"278","52e2a80b":"306",f62d4472:"326","9b4185c1":"330","044d5aa6":"332","4d54d076":"459","4bdb0d83":"496","9beb87c2":"539",ccab7630:"546","9be9f402":"552","935f2afb":"581",ac5280f2:"586",a3713279:"588",c4f5d8e4:"634",f52ebc2d:"676","1f5fb0df":"695","1be78505":"714",ffd4f506:"778","1745c531":"790","72e14192":"814","625b1ed7":"831","25b7c3f2":"847","18ba09e8":"849",a63906ba:"903","68d50eef":"992"}[e]||e,o.p+o.u(e)},(()=>{var e={354:0,869:0};o.f.j=(t,r)=>{var a=o.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(354|869)$/.test(t))e[t]=0;else{var f=new Promise(((r,f)=>a=e[t]=[r,f]));r.push(a[2]=f);var d=o.p+o.u(t),b=new Error;o.l(d,(r=>{if(o.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var f=r&&("load"===r.type?"missing":r.type),d=r&&r.target&&r.target.src;b.message="Loading chunk "+t+" failed.\n("+f+": "+d+")",b.name="ChunkLoadError",b.type=f,b.request=d,a[1](b)}}),"chunk-"+t,t)}},o.O.j=t=>0===e[t];var t=(t,r)=>{var a,f,d=r[0],b=r[1],n=r[2],c=0;if(d.some((t=>0!==e[t]))){for(a in b)o.o(b,a)&&(o.m[a]=b[a]);if(n)var i=n(o)}for(t&&t(r);c{"use strict";var e,t,r,a,f,d={},b={};function o(e){var t=b[e];if(void 0!==t)return t.exports;var r=b[e]={id:e,loaded:!1,exports:{}};return d[e].call(r.exports,r,r.exports,o),r.loaded=!0,r.exports}o.m=d,o.c=b,e=[],o.O=(t,r,a,f)=>{if(!r){var d=1/0;for(i=0;i=f)&&Object.keys(o.O).every((e=>o.O[e](r[n])))?r.splice(n--,1):(b=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[r,a,f]},o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,o.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var f=Object.create(null);o.r(f);var d={};t=t||[null,r({}),r([]),r(r)];for(var b=2&a&&e;"object"==typeof b&&!~t.indexOf(b);b=r(b))Object.getOwnPropertyNames(b).forEach((t=>d[t]=()=>e[t]));return d.default=()=>e,o.d(f,d),f},o.d=(e,t)=>{for(var r in t)o.o(t,r)&&!o.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((t,r)=>(o.f[r](e,t),t)),[])),o.u=e=>"assets/js/"+({13:"9d9f8394",61:"1f391b9e",87:"e505b3a5",134:"393be207",138:"27d9d47d",146:"2140bf91",151:"0bfe2fe2",158:"0276dc25",228:"dea0f9ea",245:"f9f76190",278:"87124b4e",306:"52e2a80b",326:"f62d4472",330:"9b4185c1",332:"044d5aa6",401:"17896441",459:"4d54d076",496:"4bdb0d83",539:"9beb87c2",546:"ccab7630",552:"9be9f402",581:"935f2afb",586:"ac5280f2",588:"a3713279",634:"c4f5d8e4",676:"f52ebc2d",695:"1f5fb0df",714:"1be78505",778:"ffd4f506",790:"1745c531",814:"72e14192",831:"625b1ed7",847:"25b7c3f2",849:"18ba09e8",903:"a63906ba",992:"68d50eef"}[e]||e)+"."+{13:"cdcd7a26",61:"6f0bef76",87:"ef765b4b",90:"fffd597a",134:"2c0ad88d",138:"30b89259",146:"f2e2506e",151:"055a0f41",158:"31602082",228:"154146d6",245:"04df3d8f",278:"78387f6b",306:"2d1ea665",326:"2688d702",330:"76280d8c",332:"f46425ff",343:"3f40ba3c",345:"8ee5f24c",401:"2d945a38",459:"be1fdcfc",496:"5a2453b6",504:"1b68801e",539:"70b0135c",546:"9d741c50",552:"e10e35ea",581:"f58a9a76",586:"a02d052e",588:"c25e1b3a",593:"8fb47887",634:"d5b77601",676:"6d2e7ffb",695:"3ab253cd",714:"93b17e9c",778:"eb67f751",790:"44ad1d35",814:"c3b3a598",831:"af99ed07",847:"a717e408",849:"2035098a",896:"acea2065",903:"7c16ee9f",913:"dd95d7ef",992:"ad0d74b4"}[e]+".js",o.miniCssF=e=>"assets/css/styles.de060916.css",o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},f="dashy:",o.l=(e,t,r,d)=>{if(a[e])a[e].push(t);else{var b,n;if(void 0!==r)for(var c=document.getElementsByTagName("script"),i=0;i{b.onerror=b.onload=null,clearTimeout(l);var f=a[e];if(delete a[e],b.parentNode&&b.parentNode.removeChild(b),f&&f.forEach((e=>e(r))),t)return t(r)},l=setTimeout(u.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=u.bind(null,b.onerror),b.onload=u.bind(null,b.onload),n&&document.head.appendChild(b)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.p="/",o.gca=function(e){return e={17896441:"401","9d9f8394":"13","1f391b9e":"61",e505b3a5:"87","393be207":"134","27d9d47d":"138","2140bf91":"146","0bfe2fe2":"151","0276dc25":"158",dea0f9ea:"228",f9f76190:"245","87124b4e":"278","52e2a80b":"306",f62d4472:"326","9b4185c1":"330","044d5aa6":"332","4d54d076":"459","4bdb0d83":"496","9beb87c2":"539",ccab7630:"546","9be9f402":"552","935f2afb":"581",ac5280f2:"586",a3713279:"588",c4f5d8e4:"634",f52ebc2d:"676","1f5fb0df":"695","1be78505":"714",ffd4f506:"778","1745c531":"790","72e14192":"814","625b1ed7":"831","25b7c3f2":"847","18ba09e8":"849",a63906ba:"903","68d50eef":"992"}[e]||e,o.p+o.u(e)},(()=>{var e={354:0,869:0};o.f.j=(t,r)=>{var a=o.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(354|869)$/.test(t))e[t]=0;else{var f=new Promise(((r,f)=>a=e[t]=[r,f]));r.push(a[2]=f);var d=o.p+o.u(t),b=new Error;o.l(d,(r=>{if(o.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var f=r&&("load"===r.type?"missing":r.type),d=r&&r.target&&r.target.src;b.message="Loading chunk "+t+" failed.\n("+f+": "+d+")",b.name="ChunkLoadError",b.type=f,b.request=d,a[1](b)}}),"chunk-"+t,t)}},o.O.j=t=>0===e[t];var t=(t,r)=>{var a,f,d=r[0],b=r[1],n=r[2],c=0;if(d.some((t=>0!==e[t]))){for(a in b)o.o(b,a)&&(o.m[a]=b[a]);if(n)var i=n(o)}for(t&&t(r);c Alternate Views & Opening Methods | Dashy - +

Alternate Views & Opening Methods

Views#

Dashy has three different views:

  • Default View - This is the main homepage with sections in a grid layout
  • Workspace View - Items displayed on the side, and are launched within Dashy
  • Minimal View - A clean + simple tabbed view

You can switch between views using the dropdown in the top-right corner. Set your chosen Starting View with appConfig.startingView. Click the page title at any time to go back to your selected starting view.

Default#

This is the main page that you will land on when you first launch the application. Here all of your sections (with items + widgets) are visible in a grid layout.

Example of Default View
Demo

Workspace#

The workspace view displays your links in a sidebar on the left-hand side, and apps are launched inside an iframe without having to leave Dashy. This enables you to use all of your self-hosted apps from one place, and makes multi-tasking easy.

You can specify a default app to be opened when you land on the workspace, by setting appConfig.workspaceLandingUrl: https://app-to-open/. If this app exists within your sections.items, then the corresponding section will also be expanded.

You can also opt to keep previously opened websites/ apps open in the background, by setting appConfig.enableMultiTasking: true. This comes at the cost of performance, but does mean that your session with each app is preserved, enabling you to quickly switch between them.

Example of Workspace View
Workspace view demo

Minimal View#

The minimal view aims to be super fast and simple, and can be used as a browser startpage. Items are grouped into a tab view, and the last opened tab will be remembered. Similar to the main view, you can search and launch items just by typing, and right-clicking will show more options (like open in modal, workspace or new tab).

Example of Minimal View
Workspace view demo

Opening Methods#

Dashy supports several different ways to launch your apps. The primary opening method for each app can be specified using the target attribute, with a value of one of the following:

  • sametab - The app will be launched in the current tab
  • newtab - The app will be launched in a new tab
  • top - Opens in the top-most browsing context, useful if you're accessing Dashy through an iframe
  • modal - Launch app in a resizable/ movable popup modal on the current page
  • workspace - Changes to Workspace view, and launches app

You can also set a default opening method, which will be applied to all items that don't have a specified target, using appConfig.defaultOpeningMethod, to one of the above values.

Even if the target is not set (or is set to sametab), you can still launch any given app in an alternative method. Either right-click to see all options, or use one of the keyboard shortcuts: Alt + Click will open the modal, and Ctrl + Click will open in a new tab.

If you don't like the custom context menu, it can be disabled by setting appConfig.disableContextMenu: true.

If you get a 'Refused to Connect' error in the modal or workspace views, then the target app has it's X-Frame-Options HTTP set to block requests from embedded content. You can easily fix this by setting this header to ALLOW, for instructions on how to do so, see the Troubleshooting Docs.

- + \ No newline at end of file diff --git a/docs/authentication/index.html b/docs/authentication/index.html index 938c31dc..13725703 100644 --- a/docs/authentication/index.html +++ b/docs/authentication/index.html @@ -6,20 +6,20 @@ Authentication | Dashy - +

Authentication

[!IMPORTANT] -Dashy's built-in auth is not indented to protect a publicly hosted instance against unauthorized access. Instead you should use an auth provider compatible with your reverse proxy, or access Dashy via your VPN.

In cases where Dashy is only accessibly within your home network, and you just want to add a login page, then the built-in auth may be sufficient, but keep in mind that configuration can still be accessed.

Built-In Auth#

Dashy has a basic login page included, and frontend authentication. You can enable this by adding users to the auth section under appConfig in your conf.yml. If this section is not specified, then no authentication will be required to access the app, and the homepage will resolve to your dashboard.

Setting Up Authentication#

The auth property takes an array of users. Each user needs to include a username, hash and optional user type (admin or normal). The hash property is a SHA-256 Hash of your desired password.

For example:

appConfig:  auth:    users:    - user: alicia      hash: 4D1E58C90B3B94BCAD9848ECCACD6D2A8C9FBC5CA913304BBA5CDEAB36FEEFA3      type: admin    - user: bob      hash: 5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8

Hash Password#

Dashy uses SHA-256 Hash, a 64-character string, which you can generate using an online tool, such as this one or CyberChef (which can be self-hosted/ ran locally).

A hash is a one-way cryptographic function, meaning that it is easy to generate a hash for a given password, but very hard to determine the original password for a given hash. This means, that so long as your password is long, strong and unique, it is safe to store its hash in the clear. Having said that, you should never reuse passwords, hashes can be cracked by iterating over known password lists, generating a hash of each.

Logging In and Out#

Once authentication is enabled, so long as there is no valid token in cookie storage, the application will redirect the user to the login page. When the user enters credentials in the login page, they will be checked, and if valid, then a token will be generated, and they can be redirected to the home page. If credentials are invalid, then an error message will be shown, and they will remain on the login page. Once in the application, to log out: the user can click the logout button (in the top-right), which will clear cookie storage, causing them to be redirected back to the login page.

Enabling Guest Access#

With authentication set up, by default no access is allowed to your dashboard without first logging in with valid credentials. Guest mode can be enabled to allow for read-only access to a secured dashboard by any user, without the need to log in. A guest user cannot write any changes to the config file, but can apply modifications locally (stored in their browser). You can enable guest access, by setting appConfig.auth.enableGuestAccess: true.

Granular Access#

You can use the following properties to make certain pages, sections or items only visible to some users, or hide pages, sections and items from guests.

  • hideForUsers - Page, Section or Item will be visible to all users, except for those specified in this list
  • showForUsers - Page, Section or Item will be hidden from all users, except for those specified in this list
  • hideForGuests - Page, Section or Item will be visible for logged in users, but not for guests

For Example:

pages:  - name: Home Lab    path: home-lab.yml    displayData:      showForUsers: [admin]  - name: Intranet    path: intranet.yml    displayData:      hideForGuests: true      hideForUsers: [alicia, bob]
- name: Code Analysis & Monitoring  icon: fas fa-code  displayData:    cols: 2    hideForUsers: [alicia, bob]  items:    ...
- name: Deployment Pipelines  icon: fas fa-rocket  displayData:    hideForGuests: true  items:    - title: Hide Me      displayData:        hideForUsers: [alicia, bob]

Permissions#

Any user who is not an admin (with type: admin) will not be able to write changes to disk.

You can also prevent any user from writing changes to disk, using preventWriteToDisk. Or prevent any changes from being saved locally in browser storage, using preventLocalSave. Both properties can be found under appConfig.

To disable all UI config features, including View Config, set disableConfiguration. Alternatively you can disable UI config features for all non admin users by setting disableConfigurationForNonAdmin to true.

Security#

With basic auth, all logic is happening on the client-side, which could mean a skilled user could manipulate the code to view parts of your configuration, including the hash. If the SHA-256 hash is of a common password, it may be possible to determine it, using a lookup table, in order to find the original password. Which can be used to manually generate the auth token, that can then be inserted into session storage, to become a valid logged in user. Therefore, you should always use a long, strong and unique password, and if you instance contains security-critical info and/ or is exposed directly to the internet, and alternative authentication method may be better. The purpose of the login page is merely to prevent immediate unauthorized access to your homepage.

⬆️ Back to Top


Keycloak#

Dashy also supports using a Keycloak authentication server. The setup for this is a bit more involved, but it gives you greater security overall, useful for if your instance is exposed to the internet.

Keycloak is a Java-based open source, high-performance, secure authentication system, supported by RedHat. It is easy to setup (with Docker), and enables you to secure multiple self-hosted applications with single-sign-on using standard protocols (OpenID Connect, OAuth 2.0, SAML 2.0 and social login). It's also very customizable, you can write or use custom themes, plugins, password policies and more. +Dashy's built-in auth is not indented to protect a publicly hosted instance against unauthorized access. Instead you should use an auth provider compatible with your reverse proxy, or access Dashy via your VPN.

In cases where Dashy is only accessibly within your home network, and you just want to add a login page, then the built-in auth may be sufficient, but keep in mind that configuration can still be accessed.

Built-In Auth#

Dashy has a basic login page included, and frontend authentication. You can enable this by adding users to the auth section under appConfig in your conf.yml. If this section is not specified, then no authentication will be required to access the app, and the homepage will resolve to your dashboard.

Setting Up Authentication#

The auth property takes an array of users. Each user needs to include a username, hash and optional user type (admin or normal). The hash property is a SHA-256 Hash of your desired password.

For example:

appConfig:  auth:    users:    - user: alicia      hash: 4D1E58C90B3B94BCAD9848ECCACD6D2A8C9FBC5CA913304BBA5CDEAB36FEEFA3      type: admin    - user: bob      hash: 5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8

Hash Password#

Dashy uses SHA-256 Hash, a 64-character string, which you can generate using an online tool, such as this one or CyberChef (which can be self-hosted/ ran locally).

A hash is a one-way cryptographic function, meaning that it is easy to generate a hash for a given password, but very hard to determine the original password for a given hash. This means, that so long as your password is long, strong and unique, it is safe to store its hash in the clear. Having said that, you should never reuse passwords, hashes can be cracked by iterating over known password lists, generating a hash of each.

Logging In and Out#

Once authentication is enabled, so long as there is no valid token in cookie storage, the application will redirect the user to the login page. When the user enters credentials in the login page, they will be checked, and if valid, then a token will be generated, and they can be redirected to the home page. If credentials are invalid, then an error message will be shown, and they will remain on the login page. Once in the application, to log out: the user can click the logout button (in the top-right), which will clear cookie storage, causing them to be redirected back to the login page.

Enabling Guest Access#

With authentication set up, by default no access is allowed to your dashboard without first logging in with valid credentials. Guest mode can be enabled to allow for read-only access to a secured dashboard by any user, without the need to log in. A guest user cannot write any changes to the config file, but can apply modifications locally (stored in their browser). You can enable guest access, by setting appConfig.auth.enableGuestAccess: true.

Granular Access#

You can use the following properties to make certain pages, sections or items only visible to some users, or hide pages, sections and items from guests.

  • hideForUsers - Page, Section or Item will be visible to all users, except for those specified in this list
  • showForUsers - Page, Section or Item will be hidden from all users, except for those specified in this list
  • hideForGuests - Page, Section or Item will be visible for logged in users, but not for guests

For Example:

pages:  - name: Home Lab    path: home-lab.yml    displayData:      showForUsers: [admin]  - name: Intranet    path: intranet.yml    displayData:      hideForGuests: true      hideForUsers: [alicia, bob]
- name: Code Analysis & Monitoring  icon: fas fa-code  displayData:    cols: 2    hideForUsers: [alicia, bob]  items:    ...
- name: Deployment Pipelines  icon: fas fa-rocket  displayData:    hideForGuests: true  items:    - title: Hide Me      displayData:        hideForUsers: [alicia, bob]

Permissions#

Any user who is not an admin (with type: admin) will not be able to write changes to disk.

You can also prevent any user from writing changes to disk, using preventWriteToDisk. Or prevent any changes from being saved locally in browser storage, using preventLocalSave. Both properties can be found under appConfig.

To disable all UI config features, including View Config, set disableConfiguration. Alternatively you can disable UI config features for all non admin users by setting disableConfigurationForNonAdmin to true.

Security#

With basic auth, all logic is happening on the client-side, which could mean a skilled user could manipulate the code to view parts of your configuration, including the hash. If the SHA-256 hash is of a common password, it may be possible to determine it, using a lookup table, in order to find the original password. Which can be used to manually generate the auth token, that can then be inserted into session storage, to become a valid logged in user. Therefore, you should always use a long, strong and unique password, and if you instance contains security-critical info and/ or is exposed directly to the internet, and alternative authentication method may be better. The purpose of the login page is merely to prevent immediate unauthorized access to your homepage.

⬆️ Back to Top


Keycloak#

Dashy also supports using a Keycloak authentication server. The setup for this is a bit more involved, but it gives you greater security overall, useful for if your instance is exposed to the internet.

Keycloak is a Java-based open source, high-performance, secure authentication system, supported by RedHat. It is easy to setup (with Docker), and enables you to secure multiple self-hosted applications with single-sign-on using standard protocols (OpenID Connect, OAuth 2.0, SAML 2.0 and social login). It's also very customizable, you can write or use custom themes, plugins, password policies and more. The following guide will walk you through setting up Keycloak with Dashy. If you already have a Keycloak instance configured, then skip to Step 3.

1. Deploy Keycloak#

First thing to do is to spin up a new instance of Keycloak. You will need Docker installed, and can then choose a tag, and pull the container from quay.io/keycloak/keycloak

Use the following run command, replacing the attributes (default credentials, port and name), or incorporate this into your docker-compose file.

docker run -d \  -p 8081:8080 \  --name auth-server \  -e KEYCLOAK_USER=admin \  -e KEYCLOAK_PASSWORD=admin \  quay.io/keycloak/keycloak:15.0.2

If you need to pull from DockerHub, a non-official image is available here. Or if you would prefer not to use Docker, you can also directly install Keycloak from source, following this guide.

You should now be able to access the Keycloak web interface, using the port specified above (e.g. http://127.0.0.1:8081), login with the default credentials, and when prompted create a new password.

2. Setup Keycloak Users#

Before we can use Keycloak, we must first set it up with some users. Keycloak uses Realms (similar to tenants) to create isolated groups of users. You must create a Realm before you will be able to add your first user.

  1. Head over to the admin console
  2. In the top-left corner there is a dropdown called 'Master', hover over it and then click 'Add Realm'
  3. Give your realm a name, and hit 'Create'

You can now create your first user.

  1. In the left-hand menu, click 'Users', then 'Add User'
  2. Fill in the form, including username and hit 'Save'
  3. Under the 'Credentials' tab, give the new user an initial password. They will be prompted to change this after first login

The last thing we need to do in the Keycloak admin console is to create a new client

  1. Within your new realm, navigate to 'Clients' on the left-hand side, then click 'Create' in the top-right
  2. Choose a 'Client ID', set 'Client Protocol' to 'openid-connect', and for 'Valid Redirect URIs' put a URL pattern to where you're hosting Dashy (if you're just testing locally, then * is fine), and do the same for the 'Web Origins' field
  3. Make note of your client-id, and click 'Save'

3. Enable Keycloak in Dashy Config File#

Now that your Keycloak instance is up and running, all that's left to do is to configure Dashy to use it. Under appConfig, set auth.enableKeycloak: true, then fill in the details in auth.keycloak, including: serverUrl - the URL where your Keycloak instance is hosted, realm - the name you gave your Realm, and clientId - the Client ID you chose. For example:

appConfig:  ...  auth:    enableKeycloak: true    keycloak:      serverUrl: 'http://localhost:8081'      realm: 'alicia-homelab'      clientId: 'dashy'

Note that if you are using Keycloak V 17 or older, you will also need to set legacySupport: true (also under appConfig.auth.keycloak). This is because the API endpoint was updated in later versions.

If you use Keycloak with an external Identity Provier, you can set the idpHint: 'alias-of-kc-idp' option to allow the IdP Hint to be passed to Keycloak. This will cause Keycloak to skip its login page and redirect the user directly to the specified IdP's login page. Set to the value of the 'Alias' field of the desired IdP as defined in Keycloak under 'Identity Providers'.

4. Add groups and roles (Optional)#

Keycloak allows you to assign users roles and groups. You can use these values to configure who can access various sections or items in Dashy. Keycloak server administration and configuration is a deep topic; please refer to the server admin guide to see details about creating and assigning roles and groups. Once you have groups or roles assigned to users you can configure access under each section or item displayData.showForKeycloakUser and displayData.hideForKeycloakUser. Both show and hide configurations accept a list of groups and roles that limit access. If a users data matches one or more items in these lists they will be allowed or excluded as defined.

sections:  - name: DeveloperResources    displayData:      showForKeycloakUsers:        roles: ['canViewDevResources']      hideForKeycloakUsers:        groups: ['ProductTeam']    items:      - title: Not Visible for developers        displayData:          hideForKeycloakUsers:            groups: ['DevelopmentTeam']

Depending on how you're hosting Dashy and Keycloak, you may also need to set some HTTP headers, to prevent a CORS error. This would typically be the Access-Control-Allow-Origin [URL-of Dashy] on your Keycloak instance. See the Setting Headers guide in the management docs for more info.

Your app is now secured :) When you load Dashy, it will redirect to your Keycloak login page, and any user without valid credentials will be prevented from accessing your dashboard.

From within the Keycloak console, you can then configure things like time-outs, password policies, etc. You can also backup your full Keycloak config, and it is recommended to do this, along with your Dashy config. You can spin up both Dashy and Keycloak simultaneously and restore both applications configs using a docker-compose.yml file, and this is recommended.


Alternative Authentication Methods#

If you are self-hosting Dashy, and require secure authentication to prevent unauthorized access, then you can either use Keycloak, or one of the following options:

Authentication Server#

Authelia#

Authelia is an open-source full-featured authentication server, which can be self-hosted and either on bare metal, in a Docker container or in a Kubernetes cluster. It allows for fine-grained access control rules based on IP, path, users etc, and supports 2FA, simple password access or bypass policies for your domains.

  • git clone https://github.com/authelia/authelia.git
  • cd authelia/examples/compose/lite
  • Modify the users_database.yml the default username and password is authelia
  • Modify the configuration.yml and docker-compose.yml with your respective domains and secrets
  • docker-compose up -d

For more information, see the Authelia docs

VPN#

A catch-all solution to accessing services running from your home network remotely is to use a VPN. It means you do not need to worry about implementing complex authentication rules, or trusting the login implementation of individual applications. However it can be inconvenient to use on a day-to-day basis, and some public and corporate WiFi block VPN connections. Two popular VPN protocols are OpenVPN and WireGuard

IP-Based Access#

If you have a static IP or use a VPN to access your running services, then you can use conditional access to block access to Dashy from everyone except users of your pre-defined IP address. This feature is offered by most cloud providers, and supported by most web servers.

Apache#

In Apache, this is configured in your .htaccess file in Dashy's root folder, and should look something like:

Order Deny,AllowDeny from allAllow from [your-ip]

NGINX#

In NGINX you can specify control access rules for a given site in your nginx.conf or hosts file. For example:

server {    listen 80;    server_name www.dashy.example.com;    location / {        root /path/to/dashy/;        passenger_enabled on;        allow [your-ip];        deny all;    }  }

Caddy#

In Caddy, Request Matchers can be used to filter requests

dashy.site {    @public_networks not remote_ip [your-ip]    respond @public_networks "Access denied" 403}

Web Server Authentication#

Most web servers make password protecting certain apps very easy. Note that you should also set up HTTPS and have a valid certificate in order for this to be secure.

Apache#

First crate a .htaccess file in Dashy's route directory. Specify the auth type and path to where you want to store the password file (usually the same folder). For example:

AuthType BasicAuthName "Please Sign into Dashy"AuthUserFile /path/dashy/.htpasswdrequire valid-user

Then create a .htpasswd file in the same directory. List users and their hashed passwords here, with one user on each line, and a colon between username and password (e.g. [username]:[hashed-password]). You will need to generate an MD5 hash of your desired password, this can be done with an online tool. Your file will look something like:

alicia:$apr1$jv0spemw$RzOX5/GgY69JMkgV6u16l0

NGINX#

NGINX has an authentication module which can be used to add passwords to given sites, and is fairly simple to set up. Similar to above, you will need to create a .htpasswd file. Then just enable auth and specify the path to that file, for example:

location / {  auth_basic "closed site";  auth_basic_user_file conf/htpasswd;}

Caddy#

Caddy has a basic-auth directive, where you specify a username and hash. The password hash needs to be base-64 encoded, the caddy hash-password command can help with this. For example:

basicauth /secret/* {    alicia JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX}

For more info about implementing a single sign on for all your apps with Caddy, see this tutorial

Lighttpd#

You can use the mod_auth module to secure your site with Lighttpd. Like with Apache, you need to first create a password file listing your usernames and hashed passwords, but in Lighttpd, it's usually called .lighttpdpassword.

Then in your lighttpd.conf file (usually in the /etc/lighttpd/ directory), load in the mod_auth module, and configure it's directives. For example:

server.modules += ( "mod_auth" )auth.debug = 2auth.backend = "plain"auth.backend.plain.userfile = "/home/lighttpd/.lighttpdpassword"
-$HTTP["host"] == "dashy.my-domain.net" {  server.document-root = "/home/lighttpd/dashy.my-domain.net/http"  server.errorlog = "/var/log/lighttpd/dashy.my-domain.net/error.log"  accesslog.filename = "/var/log/lighttpd/dashy.my-domain.net/access.log"  auth.require = (    "/docs/" => (      "method" => "basic",      "realm" => "Password protected area",      "require" => "user=alicia"    )  )}

Restart your web server for changes to take effect.

OAuth Services#

There are also authentication services, such as Ory.sh, Okta, Auth0, Firebase. Implementing one of these solutions would involve some changes to the Auth.js file, but should be fairly straightforward.

Static Site Hosting Providers#

If you are hosting Dashy on a cloud platform, you will probably find that it has built-in support for password protected access to web apps. For more info, see the relevant docs for your provider, for example: Netlify Password Protection, Cloudflare Access, AWS Cognito, Azure Authentication and Vercel Password Protection.

⬆️ Back to Top

- +$HTTP["host"] == "dashy.my-domain.net" { server.document-root = "/home/lighttpd/dashy.my-domain.net/http" server.errorlog = "/var/log/lighttpd/dashy.my-domain.net/error.log" accesslog.filename = "/var/log/lighttpd/dashy.my-domain.net/access.log" auth.require = ( "/docs/" => ( "method" => "basic", "realm" => "Password protected area", "require" => "user=alicia" ) )}

Restart your web server for changes to take effect.

OAuth Services#

There are also authentication services, such as Ory.sh, Okta, Auth0, Firebase. Implementing one of these solutions would involve some changes to the Auth.js file, but should be fairly straightforward.

Static Site Hosting Providers#

If you are hosting Dashy on a cloud platform, you will probably find that it has built-in support for password protected access to web apps. For more info, see the relevant docs for your provider, for example: Netlify Password Protection, Cloudflare Access, AWS Cognito, Azure Authentication and Vercel Password Protection.

⬆️ Back to Top

+ \ No newline at end of file diff --git a/docs/backup-restore/index.html b/docs/backup-restore/index.html index 1810277f..41490209 100644 --- a/docs/backup-restore/index.html +++ b/docs/backup-restore/index.html @@ -6,7 +6,7 @@ Cloud Backup and Restore | Dashy - + @@ -15,7 +15,7 @@ workers_dev = trueroute = "example.com/*"zone_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"account_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" kv_namespaces = [ { binding = "DASHY_CLOUD_BACKUP", id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }]

Complete index.js#

  • Write code to handle your requests, and interact with any other data sources in this file
  • Generally, this is done within an event listener for 'fetch', and returns a promise
    • For Example:
addEventListener('fetch', event => {  event.respondWith(handleRequest(event.request))})
 async function handleRequest(request) {  return new Response('Hello World!', {    headers: { 'content-type': 'text/plain' },  })}
  • For the code used for Dashy's cloud service, see here

Commands#

  • wrangler dev - To start the wrangler development server
  • wrangler publish - To publish to your cloudflare account (first run wrangler login)

API#

There are four endpoints, and to keep things simple, they all use the same base URL/ route.

  • GET - Get config for a given user
    • backupId - The ID of the desired encrypted object
    • subHash - The latter half of the password hash, to verify ownership
  • POST - Save a new config object, and returns backupId
    • userData - The encrypted, compressed and stringified user config
    • subHash - The latter half of the password hash, to verify ownership
  • PUT - Update an existing config object
    • backupId - The ID of the object to update
    • subHash - Part of the hash, to verify ownership of said object
    • userData - The new data to store
  • DELETE - Delete a specified config object
    • backupId - The ID of the object to be deleted
    • subHash - Part of the password hash, to verify ownership of the object

For more info, see the API Docs.

If you are using Postman, you may find this pre-made collection helpful in getting things setup.

- + \ No newline at end of file diff --git a/docs/changelog/index.html b/docs/changelog/index.html index d283bdee..ec068e5d 100644 --- a/docs/changelog/index.html +++ b/docs/changelog/index.html @@ -6,7 +6,7 @@ Changelog | Dashy - + @@ -16,7 +16,7 @@ Fixes #544 #555

Several other changes sinc When using SSL, the server can now redirect from HTTP to HTTPS. This is enabled by default when using SSL. #538 Section context menus are now accessible on mobile, and will no longer clip off the screen. #541 Italian translations have been added. #556

✨ 2.0.4 - Dynamic Config Loading PR #528

  • conf.yml is now loaded dynamically and the app now only needs a browser refresh on config change, not a full rebuild!

🐛 2.0.3 - Bug Fixes PR #488

  • Press enter to submit login form (Re: #483)
  • Allow disabling write to local storage and disk (Re: #485)
  • Fix malformed YAML from export config (Re: #482)
  • Allow global option for useProxy (Re: #486)
  • Look into arrow key navigation error (Re: #463)
  • Disallow displaying config (Re: #455)
  • Round values in Glances Alerts widget (Re: #454)
  • Create a CPU temp widget (Re: #452)
  • Add to docs: Keycloak in Kubernetes (Re: #479)
  • Add a widget for displaying images (Re: #487)

⬆️ 2.0.2 - Dependency Updates PR #471

  • Updates Alpine version for main Dockerfile
  • Updates node_modules to latest stable versions

🐛 2.0.1 - Fixes Section Height PR #462

  • Adds cutToHeight to config schema (Re: #461)
  • Removes the full-height CSS from colorful theme
  • Improved config validation warnings in JSON editor
  • Removes empty Keycloak block from appConfig editor
  • Adds typechecking to search and clear search for Safari

⚡️ 2.0.0 - Small Fixes and Docker Multi-Arch Build PR #451

  • Fixes full-height sections for mobile and Safari (Re: #432, #442)
  • Fixes empty section visible in search (Re: #447)
  • Fixes numbers omited from tag names (Re: #430)
  • Option for custom status code in status check (Re: #456, #448)
  • Adds @stuu3k's dashboard to showcase (Re: #446)
  • Switches recover and death count in Covid widget (Re: #148)
  • Improved contrast in light material theme
  • Adds new script to lint, test, build and publish a multi-architecture Docker image to various registries

💄 1.9.9 - Minor UI + Docs Updates PR #431

  • Improved theme support for widgets
  • Better widget layout in Workspace and Minimal views
  • Updates lots of the docs

✨ 1.9.8 - More Widgets and Widget Improvements PR #425

  • Fixes several minor widget issues raised by users
  • Adds several new widgets, for monitoring system
  • Better widget data requests and error handling
  • Implements widget support into Workspace view

🐛 1.9.7 - Minor UI Editor Bug fixes PR #416

  • Fixes unable to edit item bug (#415)
  • Fixes unable to add new app bug (#390)
  • Fixes nav links visibility (#389)

⚡️ 1.9.6 - Adds Proxy Support for Widget Requests PR #392

  • Refactors widget mixin to include data requests, so that code can be shared between widgets
  • Adds a Node endpoint for proxying requests server-side, used for APIs that are not CORS enabled
  • Adds option to config file for user to force proxying of requests
  • Writes a Netlify cloud function to support proxying when the app is hosted on Netlify

🐛 1.9.5 - Bug fixes and Minor Improvements PR #388

  • Adds icon.horse to supported favicon APIs
  • Fixes tile move bug, Re: #366
  • Fixes save items without title bug, Re: #377

✨ 1.9.4 - Widget Support PR #382

  • Adds support for dynamic content, through widgets
  • Adds 30+ pre-built widgets for general info and self-hosted services
  • Writes docs on widget usage

⚡️ 1.9.2 - Native SSL Support + Performance Improvements PR #326

  • Updates the server to use Express, removing serve-static, connect and body-parser
  • Adds native support for passing in self-signed SSL certificates and updates docs
  • Updates router to lazy-load additional pages (minimal, workspace, etc)
  • Changes default favicon API to allesedv, since faviconkit is down, and adds basic fallback
  • Updates GH action build scripts to fallback on context token when running on fork

💄 1.9.1 - Editor and Theming Fixes and Improvements PR #319

  • Bug fixes for interactive editor: #310, #311, #312
  • Adds option to modify text font through the UI
  • Adds two new themes: One Dark and Adventure
  • Theming stylesheet refactor, better inheritance

🐳 1.9.0 - Alpha of Dashy-Lite Docker Container PR #306

  • Create an Alpine-based container, that serves the built app up with plain NGINX, instead of Node.
  • This is much lighter, but doesn't currently support any of the server-side actions (like status-checks, and writing changes to disk)

✨ 1.8.9 - All New Interactive Config Editor PR #298

  • Builds a new UI-based config editor
  • Support for sections, items, app config and page info
  • Live preview, and undoing of local changes
  • Export config or write changes to disk through UI

✨ 1.8.8 - Improved Item Targets PR #292

  • Adds support for _top and _parent anchor targets on items, Re: #289
  • Adds appConfig.defaultOpeningMethod option to specify default target
  • Adds new icons to show items opening method on hover
  • Refactors target checking, updates item target docs and schema

⚡️ 1.8.7 - Bug Fixes and Improvements PR #273

  • Clean URLs without the hash, now using history-mode routing
  • New initial main example conf.yml
  • Minor UI style updates and fixes
  • Support for single section view
  • A new theme, soft-glow
  • Container security in management docs, and other things
  • Bug fixes, including missing Firefox favicon and fix custom icon paths with base_url

⚡️ 1.8.6 - Implementation of VueX PR: #271

  • New state management pattern, which should lead to a more organized code base long term, and will also make building out the new UI editor significantly easier to do in a clean and reliable way

💄 1.8.5 - Lots of Requested UI Improvements PR #261

  • Adds an option for landing URL in workspace, Re: #255
  • Switches to a new API for generative icons, Re: #163
  • Adds new tab functionality to Workspace, Re: #254
  • Remove CSS validation in style editor, Re: #259
  • Cap item description at 2 lines, Re: #250
  • Adds native support for common homelab icons, using dashboard-icons
  • Improves general responsiveness of home page sections positioning
  • Updates, fixes and adds a bunch of actions for easier repo management

✨ 1.8.4 - Custom Error Pages PR #257

  • Creates a 404 Not Found page
  • Routes any missing views to the 404 page

⚡️ 1.8.3 - Improved UX for Initial Load PR #238

  • Removes the old splash screen
  • Adds placeholder in the HTML index, which will usually be visible on initial load
  • Show progress bar on route switcher

✨ 1.8.2 - Serverless Functions for Netlify Instances PR #235

  • Previously when Dashy was deployed as a static site to Netlify, it was not possible to use several features, which required server-side code
  • This PR adds serverless cloud functions to provide most of this functionality

🩹 1.8.1 - Additional Languages, Bug Fix, and more PR #234

  • Merges 5 additional languages
  • Adds RickyCZ's dashboard to showcase
  • Fixes #323, and improves status indicator tooltip
  • Define constants for endpoints
  • Updates management, translations and readme docs

⚡️ 1.7.7 - Improved Error Handling PR #226

  • Errors can be viewed via the UI (Config menu --> App Info)
  • Service workers should be disabled by default
  • Also renames actions to be easier to maintain
  • Updates docs to include release schedule + merge strategy

✨ 1.7.6 - Adds Multi-Search Support with Bangs PR #224

  • Adds option for user to add custom search bangs, in order to specify search engine/ target app. Re: #206

🎨 1.7.5 - Improved Language Detection & UI PR #223

  • Makes the auto language detection algo smarter
  • Improves responsiveness for the language selector form

🌐 1.7.4 - Adds Spanish Translations PR #222

  • Adds Spanish language file, contributed by @lu4t

👷 1.7.3 - CI with GH Actions PR #212

  • Adds a series of GH actions for repository maintenance and administration
  • Auto-labels PR and issues, adds helpful info to PRs based on files changed
  • Lints, tests, builds and deploys the app when PR submitted
  • Checks app size, dependencies, security, accessibility etc when PR submitted
  • Closes incomplete, stale or spammy issues and leaves a comment

✨ 1.7.2 - Item Sort Options PR #203

  • Adds option for user to specify sortBy to order items within a section
  • Can sort by last clicked, most used, alphabetically and more
  • And fixes UI of the item tooltip and, if specified, will show Provider in the tooltip
  • Also improves error logging and console warning message

🐛 1.7.1 - Lots of Tiny Fixes and Improvements PR #200

  • Removes background in console art
  • Updates auto environmental variables
  • Icon image assets max height Force same Icon/Item Height #200
  • Adds an action to close spammy issues
  • Adds option to enable SRI integrity, plus refactos PWA into defaults
  • Updates privacy and security docs
  • Adds option for different favicon API for each app [FEATURE_REQUEST] Allow using different faviconApi for each items #196
  • Fixes loading of local SVG icons #199

🍻 1.7.0 - Documentation Website PR #190

  • Builds a quick website to host the docs. No code changes, but prepares for V1.7 release

✨ 1.6.9 - Web Search Feature PR #185

  • Adds ability to search the web directly from Dashy by pressing enter on the search bar
  • Adds configuration options, for setting default search engine, opening method and disabling
  • Adds text under search bar, implements into minimal view also

⚡️ 1.6.8 - Improved Loading Experience PR #183

  • During app initialization, show the build progress and status message
  • While requests are being made, show loader at top of screen
  • Also adds some UI improvements to Workspace view

⚡️ 1.6.7 - Option for non-SSL status checks plus minor things PR #182

  • Adds an option for user to use status checks with non-HTTPS services, Re: #181
  • Updates the .env template, plus the variables used in the server
  • Uses the v-cloak to hide text before it's finished loading
  • Fixed the parsing of the update-checker during build

⚡️ 1.6.6 - Improved Search & Shortcuts PR #175

  • Refactors the search algorithm to improve performance and code reusability
  • Updates search to ignore case, special characters and minor-typos
  • Adds the option for user to specify tags, which can be used for searching

✨ 1.6.5 - Adds support for Secure Authentication using Keycloak PR #174

  • Major restructure of auth config
  • Implements keycloak support, adds docs and updates schema

✨ 1.6.4 - Adds functionality for Granular Auth Control PR #171

  • Enables sections to be visible for all users except for those specified
  • Enables sections to be hidden from all users except for those specified
  • Enables sections to be hidden from guests, but visible to all authenticated users

⚡️ 1.6.3 - Dependency and Build File Updates PR #168

  • Removes any dependencies which are not 100% essential
  • Moves packages that are only used for building into devDependencies
  • Updates dependencies to latest version
  • Adds a .dockerignore, so that non-essential files are not included in the container
  • Updates deployment config files for Netlify, Heroku and GH actions
  • Made a brand new bug-report template, with input fields and validation!

✨ 1.6.2 - Support for Guest Access PR #167

  • Adds functionality for optional read-only guest access to dashboards with authentication
  • Can be enabled by setting appConfig.enableGuestAccess: true

💄 1.6.1 - Adds new Theme PR #166

  • Adds Dashy theme, for use in the dev dashboard

✨ 1.5.9 - New Minimal/ Startpage View PR #155

  • Adds a new view, called minimal view, designed to be like a light-weight startpage
  • Implemented all the required features (filtering, opening methods, icons, etc) into minimal view
  • Adds appConfig.startingView into schema, for specifying the initial default view to be loaded

✨ 1.5.8 - Multi-Tasking Support in Workspace View PR #146

  • Adds option to keep launched apps open in the background, to reduce friction when switching between websites, Re: #144
  • This can be enabled by setting appConfig.enableMultiTasking: true
  • Note that having many apps opened simultaneously, will have an impact on performance

✨ 1.5.7 - Adds Support for Material Design Icons PR #141

⚡️ 1.5.6 - Refactor + Couple of small things PR #135

  • The main Dockerfile now uses yarn.lock instead of package-lock.json
  • Adds a check to verify password is not empty in cloud backup screen
  • Improves responsiveness of config modals for mobile devices
  • Enables the user to use their own self-hosted Sentry instance
  • Removes the View Config tab of the Config menu, as not needed
  • Updates and fixes some typos in the readme

🌐 1.5.5 - Adds Missing Translations + Small UI Issues PR #129

  • Adds missing translations to several UI elements, Re: #126
  • Fixes login translations not being picked up on page load, Re: #127
  • Fixes small text overflow glitch in config icon, Re: #123
  • Several small UI improvements: height of config editor, scrollbar on theme dropdown, page height, white-on-white on material theme, etc
  • Adds an action to auto-assign reviewer based on ./.github/CODEOWNERS file

🐳 1.5.4 - Docker ARM Support PR #122

  • Adds a Dockerfile for arm64v8 and arm32v7, to support Raspberry Pi and other modern ARM-based devices
  • Sets up automated workflow to publish ARM containers to DockerHub after every new release
  • Adds documentation for running Dashy on RPi/ ARM-based devices, Re: #117

🩹 1.5.3 - UI Quick Fix PR #121

  • Downgrades and pins vue-material-tabs to 0.1.5, to prevent breaking changes. Fixes #118 p1
  • Sets auto-width for theme selector, so text doesn't wrap for long theme names. Fixes #119
  • Uses flex layout for config menu, so note doesn't overlap menu on small screens. Fixes #118 p2

🌐 1.5.2 - Adds Dutch Translations PR #120

  • Dutch language support, contributed by @evroon

🩹 1.5.1 - UI Quick Fix PR #116

  • Uses min-max width parent layout, to prevent longer languages (e.g. French) text overflow. Fixes #115

🔒 1.5.0 - Improve Robustness of Auth PR #113

  • Use both username + password for generating token, so that a change in either will log the user out
  • Prevent privilege escalation by disallowing a user from modifying their user type through the UI
  • Improve the isAuthenticated check, by taking account of empty users array

✨ 1.4.8 - Optional Crash Reports PR #112

  • Adds an optional, off by default method of getting crash reports
  • This can be enabled in appConfig.enableErrorReporting, and will not be used at all unless explicitly activated by user
  • This is needed for when a user raises a bug which is hard to fix
  • Also improves robustness of config accumulator, don't throw error when config is missing
  • Adds Privacy & Security docs

♻️ 1.4.7 - Refactor PR #110

  • Moves cloud sync dialog into the config menu, and removes icon on homepage
  • Fixes typo in Default theme name, Re #106
  • Spell checks readme
  • Updates the contributor CI action, that generates list of contributors + sponsors

📝 1.4.6 - Documentation Updates PR #108

  • Breaks many of the longer files into several more digestible articles
  • Writes repo pages including, Security, Code of Conduct, Legal, Updates license
  • Makes an automatically generated Credits page
  • Adds a contributing page, with several ways that users can help out
  • Implements this changelog, as requested in #87

🌐 1.4.5 - Adds German Translations PR #107

  • German language support, contributed by @Niklashere

✨ 1.4.4 - Adds Support for Logo Image PR #105

  • Adds option in config file for user to specify path to an image
  • If found, will display said image in the header

✨ 1.4.3 - Auto-Checks for Updates PR #101 and PR #102

  • Write a script to compare current version with git master version
  • Periodically checks for updates, and displays message to user
  • Enables user to disable update-checks in the config file
  • Checks not using vulnerable version on project-build

✨ 1.4.2 - Adds Multi-Language Support PR #99

  • Implements vue-i18n, sets object globally
  • Extracts all text to a single JSON file
  • Auto-detects users language, and applies, if availible
  • Builds a form to let user manually select their language
  • Lets users language be saved and read from local storage, or config file

✨ 1.4.1 - Adds Support for Custom Key Bindings PR #94

  • Adds new attribute under item for saving numeric key binding
  • Listens for keypress, and launches corresponding item, if found

✨ 1.4.0 - Builds a Custom Theme Configurator

  • Adds property to save custom theme variables
  • Builds UI form, with color pickers, a pallette and popup
  • Integrates the saving colors, and applying saved colors functionality

🔨 1.3.9 - Enable Custom Styesheet in Docker PR #92

  • Enables the user to pass a custom stylesheet in with Docker
  • Adds support for 1-Click deployment to Render.com

🌟 1.3.8 - Showcase #91

  • Adds @Shadowking001's screenshot to showcase

🌟 1.3.7 - Showcase PR #84

  • Adds @dtctek's screenshot to showcase

✨ 1.3.6 - Enables User to Hide Unwanted Components PR #78

  • Adds several additional options to the config, allowing the user to hide structural components that they don't need
  • Including hideHeading, hideNav, hideSearch, hideSettings, hideFooter, hideSplashScreen

✨ 1.3.5 - Adds Support for Emoji Icons PR #76

  • Enables user to use emojis for item and section icons
  • Adds a handler to convert Unicode, or Shortcode into an Emoji

🌟 1.3.4 - Showcase Addition PR #75

  • Adds @cerealconyogurt's screenshot to the showcase

💄 1.3.3 - UI Improvements PR #73

  • New style of Large item
  • 2 new color themes
  • Added CSS variables for search label and footer background
  • Improves process for auto-checking if font-awesome is needed
  • Silences non-critical warnings in production build
  • Adds new optional font-face for cyber punk
  • Shortens readme, and adds contribute links to showcase

⚡️ 1.3.0 - Custom Headers for Status Check PR #72

  • Enables user to pass custom headers to the status check endpoint
  • Enables user to use a different URL for the status check request

🌟 1.2.9 - Creates a Showcase Page PR #68

  • Adds a page in the docs for users to share their screenshots of their dashboard

✨ 1.2.8 - Adds Remember-Me Functionality into the Login Form PR #66

  • Adds a dropdown menu in the login form with various time intervals available
  • Adds appropriate expiry into session storage, in order to keep user logged in for their desired time interval

✨ 1.2.7 - Implements a Right-Click Context Menu #62

  • Built a context menu, showing all item opening methods, on right-click
  • Made a clickOutside directive, in order to close menu when user clicks away
  • Adds launching functionality, user can click to launch

⚡️ 1.2.6 - Make Font Assets Local PR #60

  • Downloaded font files to assets
  • Removed all calls to font CDN, replaced with local calls

🐛 1.2.5 - Small Fixes, and Efficiency Improvements PR #57

  • Adds correct license
  • Improves service workers, and adds serviceWorkerStatus local storage item
  • Adds missing statusCheck and statusCheckInterval docs into Configuring.md
  • Adds an About App page, containing info needed to raise a bug report
  • Adds TDLR license into main readme
  • Introduces app versioning
  • Adds safeguards into ConfigAccumalaror, to prevent error being thrown
  • Updates PR template
  • Improved Webpack build experience, with progress bar and completion notification
  • Adds new and improved icons for layout options
  • Make the Page Title into a home page link
  • Adds missing favicon, fixes #55
  • Adds assets to PWA manifest.json
  • Documents app commands in readme
  • Enable passing website as URL param to the workspace
  • Modified items, so that title text doesn't get shortened,

✨ 1.2.4 - Adds Support for Continuous Status Checking #52

  • Enables user to re-call the status check at a specified interval
  • Processes interval in ms, and updates the traffic light when required

🐛 1.2.3 - Bug Fix PR #49

  • Removes duplicate Docker env var, fixes #48

✨ 1.2.2 - Better Favicon Support

  • Enables user to force direct/ local favicon fetching
  • Adds support for additional favicon API, returning high-res app icons
  • Adds support for generative icons

🐛 1.2.1 - Bugfix #44

  • Fixes footer positioning on mobile, makes sticky, fixes #42

✨ 1.2.0 - Adds Writing Config to Disk from UI Functionality PR #43

  • Creates a new server endpoint for handling the backing up of a the file
  • Adds backup existing file functionality
  • Adds writing new file functionality
  • Does error checking, testing and adds some security parameters
  • Adds a radio button in the UI, so user chan choose save method
  • Process config within the UI, convert to YAML, and write changes to disk

🐛 1.1.8 - Bugfix #40

  • Status check tooltip was not visible in Material themes, raised in issue #39

✨ 1.1.7 - Adds Workspace View PR #38

  • Adds a new route, for the workspace view
  • Builds the sidebar, which displays the users apps
  • Loads the app into the workspace's main iframe when clicked
  • Adds some collapsing functionality, better styles, subtle animations and theme support

✨ 1.1.6 - Implements Status Indicators, and Monitoring Functionality PR #34

  • Wrote a Node endpoint for pinging the users desired services
  • Added status checking functionality in frontend
  • Build small traffic-light component to display status of users services
  • Adds animations, and handles errors
  • Writes docs, and tests code

✨ 1.1.5 - Adds Authentication / Login Functionality PR #32

  • Enables the user to protect their dashboard behind a login screen
  • Creates a Authentication handler to manage the hashing of passwords, and generation of a token
  • Build a quick login form, where user can input username and password
  • Adds a log out button

💄 1.1.4 - Support for Custom HTML Footer PR #30

  • Enables user to insert structure for the footer defined as HTML

🚀 1.1.3 - Adds Support for 1-Click Cloud Deployments PR #29

  • Support for 1-Click Deploy to Netlify
  • Support for 1-Click Deploy to Heroku

🔧 1.1.2 - Docker Efficiency Improvements PR #26

  • Writes a Node health check script, and implements into the Docker container
  • Changes default port in docker-compose, as 8080 is commonly used by other apps
  • Adds the 1-Click deploy with PWD into the readme
  • Updates dependencies
  • Adds a getting started guide to the docs
  • Adds splash screen for first load
  • Deleted unused assets
  • Makes linter run as a pre-commit hook
  • Fixes lint errors in server.js and validate-config.js

🐛 1.1.1 - Bug Fixes PR #20 + PR #21

  • Adds issue template
  • Bug fixes
    • Improves github PR and issue templates
    • Shortens readme file
    • Adds documentation in the docs folder
    • Fixes Layout tab not showing in portrait #19
    • Improves mobile performance for both the settings, config and backup pop-ups
    • Fixes issue where theme not applied on load when the settings are hidden
    • Adds minimum dimensions to modalsShortens readme file
    • Adds documentation in the docs folder
    • Adds minimum dimensions to modals

🚑️ 1.1.0 - Hotfix #18

  • Implementing the JSON validator had actually broken the entire JSON editor
  • Fixed it by remove explicit use of Ajv, and using a derivative instead

📝 1.0.5 - Documentation PR #16

  • Previously there was very little documentation, this release fixed that
  • Wrote specific docs for:
    • Getting Started
    • Configuring
    • Backup & Restore
    • Theming
    • Developing

✨ 1.0.0 - Implements Config Validation PR #13

  • Write a JSON schema for the conf.yml file
  • Wrote a validation script to compare users config against schema
  • Adds a formatter to print helpful messages about what needs fixing
  • Implements validation process into build script
  • Implements validation process into UI config configurator's validation

🔧 0.9.5 - Brand New Docker Container PR #12

  • With help from several users, a new container based on Alpine is released
  • A sample Docker Compose script is also written, and docs are updated
  • A 1-Click button for deploying to Play-with-Docker is added to the Readme

✨ 0.9.0 - Adds Hide Settings Functionality PR #11

  • Enables user to hide settings from UI
  • Users preference is saved in local storage
  • User can hide other structural elements of the UI from the config

💄 0.8.5 - Adds new Built-In Themes PR #9

  • Adds Minimal-Dark and Minimal-Light theme
  • Adds Material-Dark and Material-Light theme
  • Adds additional theme docs
  • Adds option for sections to have items too

✨ 0.8.0 - Implements Custom CSS Editor PR: #8

  • Adds a page in the config menu
  • Adds syntax highlighting, CSS validation and sanitization
  • Saves users CSS, and applies styles on page load

✨ 0.7.5 - Adds Cloud Backup and Restore Feature PR #6

  • Creates a form for entering backup ID and decryption password
  • Puts form in modal, and adds button to launch form, with custom icon
  • Implemented the cryptography stuff for end-to-end data encryption
  • Wrote and tested the backend, and deployed as a serverless function on CF workers
  • On the frontend, users input is encrypted, and passed to backend cloud function
  • Response from the backend is handles appropriately, and message displayed to the user
  • Implements the restoring from server functionality, with data integrity checks

✨ 0.7.0 - Support for Custom Nav Links PR #4

  • User can add custom nav bar links from the Config Settings menu
  • Better UI styling to the config menu
  • New icons inside buttons

✨ 0.6.5 - UI Config Editor PR #3

Adds the ability for the user to edit their configuration directly from the UI

  • Edit all section and item data using a rich JSON editor
  • Download/ backup conf.yml directly from the UI
  • Edit site meta data: title, description, footer, etc
  • Reset all locally stored data to the initial state
  • Also includes a new toast component, for subtle notifications

✨ 0.6.0 - Navbar, Footer and Background Image

  • Adds option for a custom full-size background image
  • Made footer customizable
  • Fixes error being thrown when navbar links are empty

⚡️ 0.5.5 - Improved Theming

  • Makes more specific color variables, which inherit base vars
  • Makes it possible for users to write their own theme
  • Fix some color edge cases
  • Adds docs for theming

✨ 0.5.0 - Theme Support

  • Converts all SCSS variables to CSS variables
  • Implements theme switching functionality
  • Adds a dropdown menu, enabling user to select theme
  • Adds an initial theme option to appConfig.theme
  • Saves selected theme to local storage
  • Wrote a ton of color themes

✨ 0.4.5 - Keyboard Navigation

  • Implements arrow key navigation

✨ 0.4.0 - Font Awesome Support

  • Adds support for Font-Awesome icons
  • Auto-loads font-awesome only when needed
  • Adds support for SVG icons

✨ 0.3.5 - Opening Method

  • Shows opening method on hover
  • Opening method can be specified in config, as item[n].target

🔨 0.3.0 - Docker

  • Writes a Dockerfile

🎨 0.2.5 - Code Quality, Docs and UI

  • Huge code quality overhaul, now uses AirBnB style ESLint
  • Adds in-code docs, removes unneeded code, moves reusable helpers into utils dir
  • Adds a readme, records a demo gif and adds some basic deployment docs
  • Removes dependencies which are not 100% necessary

✨ 0.2.0 - Collapsible Sections

  • Implements collapsing functionality, for less used or very long sections
  • Sections can read default state from section[n].collapsed within config
  • After change, state of each section is stored in local storage

⚡️ 0.1.5 - Search and Navigation

  • Improves instant search functionality
  • Implements keyboard navigation for selecting items
  • Launch selected item with enter, or Ctrl + Enter to open in new tab

🎉 0.1.0 - Init

Project started. Forked from Lissy93/Dash

- + \ No newline at end of file diff --git a/docs/code-of-conduct/index.html b/docs/code-of-conduct/index.html index 77a5e759..6c5f3f21 100644 --- a/docs/code-of-conduct/index.html +++ b/docs/code-of-conduct/index.html @@ -6,7 +6,7 @@ Contributor Covenant Code of Conduct | Dashy - + @@ -61,7 +61,7 @@ version 2.0, available at enforcement ladder.

For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.

- + \ No newline at end of file diff --git a/docs/configuring/index.html b/docs/configuring/index.html index 2eec67d0..6561f92d 100644 --- a/docs/configuring/index.html +++ b/docs/configuring/index.html @@ -6,13 +6,13 @@ Configuring | Dashy - +
-

Configuring

All app configuration is specified in /public/conf.yml which is in YAML Format format. If you're using Docker, this file can be passed in as a volume. Changes can either be made directly to this file, or done through the UI. From the UI you can also export, backup, reset, validate and download your configuration file.

There are three ways to edit the config#

  • Directly in the YAML file (5/5 reliability, 3/5 usability)
    • Write changes directly to the conf.yml file, optionally using one of the templates provided. This can be done in your favorite editor and uploading to your server, or directly editing the file via SSH, but the easiest method would be to use Code Server
  • UI JSON Editor (4/5 reliability, 4/5 usability)
    • From the UI, under the config menu there is a JSON editor, with built-in validation, documentation and advanced options
  • UI Visual Editor (3/5 reliability, 5/5 usability)
    • From the UI, enter the Interactive Edit Mode, then click any part of the page to edit. Changes are previewed live, and then saved to disk
  • REST API (Coming soon)
    • Programmatically edit config either through the command line, using a script or a third-party application

Tips#

  • You may find it helpful to look at some sample config files to get you started, a collection of which can be found here
  • You can check that your config file fits the schema, by running yarn validate-config
  • After modifying your config, the app needs to be recompiled, by running yarn build - this happens automatically if you're using Docker
  • It is recommended to keep a backup of your config file. You can download it under Config menu, or use the Cloud Backup feature.
  • You can make use of YAML features, like anchors, comments, multi-line strings, etc to reuse attributes and keep your config file readable
  • Once you have finished configuring your dashboard, you can choose to disable UI config if you wish
  • All fields are optional, unless otherwise stated.

The following file provides a reference of all supported configuration options.

Contents#


Top-Level Fields#

FieldTypeRequiredDescription
pageInfoobjectRequiredBasic meta data like title, description, nav bar links, footer text. See pageInfo
appConfigobjectOptionalSettings related to how the app functions, including API keys and global styles. See appConfig
sectionsarrayRequiredAn array of sections, each containing an array of items, which will be displayed as links. See section
pagesarrayOptionalAn array additional config files, used for multi-page dashboards. See pages

⬆️ Back to Top

PageInfo#

FieldTypeRequiredDescription
titlestringRequiredYour dashboard title, displayed in the header and browser tab
descriptionstringOptionalDescription of your dashboard, also displayed as a subtitle
navLinksarrayOptionalOptional list of a maximum of 6 links, which will be displayed in the navigation bar. See navLinks
footerTextstringOptionalText to display in the footer (note that this will override the default footer content). This can also include HTML and inline CSS
logostringOptionalThe path to an image to display in the header (to the right of the title). This can be either local, where / is the root of ./public, or any remote image, such as https://i.ibb.co/yhbt6CY/dashy.png. It's recommended to scale your image down, so that it doesn't impact load times

⬆️ Back to Top

pageInfo.navLinks (optional)#

FieldTypeRequiredDescription
titlestringRequiredThe text to display on the link button
pathstringRequiredThe URL to navigate to when clicked. Can be relative (e.g. /about) or absolute (e.g. https://example.com or http://192.168.1.1)
targetstringOptionalThe opening method (external links only). Can be either newtab, sametab, top or parent. Defaults to newtab

⬆️ Back to Top

pages[] (optional)#

FieldTypeRequiredDescription
namestringRequiredA unique name for that page
pathstringRequiredThe path (local or remote) to the config file to use.
For files located within /public, you only need to specify filename, for externally hosted files you must include the full URL

⬆️ Back to Top

appConfig (optional)#

FieldTypeRequiredDescription
languagestringOptionalThe 2 (or 4-digit) ISO 639-1 code for your language, e.g. en or en-GB. This must be a language that the app has already been translated into. If your language is unavailable, Dashy will fallback to English. By default Dashy will attempt to auto-detect your language, although this may not work on some privacy browsers.
startingViewenumOptionalWhich page to load by default, and on the base page or domain root. You can still switch to different views from within the UI. Can be either default, minimal or workspace. Defaults to default
defaultOpeningMethodenumOptionalThe default opening method for items, if no target is specified for a given item. Can be either newtab, sametab, modal, workspace, clipboard, top or parent. Defaults to newtab
statusCheckbooleanOptionalWhen set to true, Dashy will ping each of your services and display their status as a dot next to each item. This can be overridden by setting statusCheck under each item. Defaults to false
statusCheckIntervalnumberOptionalThe number of seconds between checks. If set to 0 then service will only be checked on initial page load, which is usually the desired functionality. If value is less than 10 you may experience a hit in performance. Defaults to 0
webSearchobjectOptionalConfiguration options for the web search feature, set your default search engine, opening method or disable web search. See webSearch
backgroundImgstringOptionalPath to an optional full-screen app background image. This can be either remote (http) or local (relative to /app/public/item-icons/ inside the container). Note that this will slow down initial load
enableFontAwesomebooleanOptionalIf set to true font-awesome will be loaded, if set to false they will not be. if left blank font-awesome will be enabled only if required by 1 or more icons
enableMaterialDesignIconsbooleanOptionalIf set to true mdi icons will be loaded, if set to false they will not be. Where true is enabled, if left blank material design icons will be enabled only if required by 1 or more icons
fontAwesomeKeystringOptionalIf you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. 13014ae648)
faviconApienumOptionalOnly applicable if you are using favicons for item icons. Specifies which service to use to resolve favicons. Set to local to do this locally, without using an API. Services running locally will use this option always. Available options are: local, faviconkit, iconhorse, google, clearbit, webmasterapi and allesedv. Defaults to faviconkit. See Icons for more info
authobjectOptionalAll settings relating to user authentication. See auth
defaultIconstringOptionalAn icon to be applied to any items, which don't already have an icon set. See Icon Docs for more info
layoutenumOptionalLayout for homepage, either horizontal, vertical or auto. Defaults to auto. This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified and overridden from the UI.
iconSizeenumOptionalThe size of link items / icons. Can be either small, medium, or large. Defaults to medium. This can also be set directly from the UI.
colCountnumberOptionalThe number of columns of sections displayed on the homepage, using the default view. Should be in integer between 1 and 8. Note that by default this is applied responsively, based on current screen size, and specifying a value here will override this behavior, which may not be desirable.
themestringOptionalThe default theme for first load (you can change this later from the UI)
cssThemesstring[]OptionalAn array of custom theme names which can be used in the theme switcher dropdown
customColorsobjectOptionalEnables you to apply a custom color palette to any given theme. Use the theme name (lowercase) as the key, for an object including key-value-pairs, with the color variable name as keys, and 6-digit hex code as value. See Theming for more info
externalStyleSheetstring or string[]OptionalEither a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI
customCssstringOptionalRaw CSS that will be applied to the page. This can also be set from the UI. Please minify it first.
hideComponentsobjectOptionalA list of key page components (header, footer, search, settings, etc) that are present by default, but can be removed using this option. See appConfig.hideComponents
routingModestringOptionalCan be either hash or history. Determines the URL format for sub-pages, hash mode will look like /#/home whereas with history mode available you have nice clean URLs, like /home. For more info, see the Vue docs. If you're hosting Dashy with a custom BASE_URL, you will find that a bit of extra server config is necessary to get history mode working, so here you may want to instead use hash mode.Defaults to history.
enableMultiTaskingbooleanOptionalIf set to true, will keep apps open in the background when in the workspace view. Useful for quickly switching between multiple sites, and preserving their state, but comes at the cost of performance.
workspaceLandingUrlstringOptionalThe URL or an app, service or website to launch when the workspace view is opened, before another service has been launched
preventWriteToDiskbooleanOptionalIf set to true, users will be prevented from saving config changes to disk through the UI
preventLocalSavebooleanOptionalIf set to true, users will be prevented from applying config changes to local storage
disableConfigurationbooleanOptionalIf set to true, no users will be able to view or edit the config through the UI
disableConfigurationForNonAdminbooleanOptionalIf set to true, only admin users will be able to view or edit the config through the UI. disableConfiguration must not be set to true.
widgetsAlwaysUseProxybooleanOptionalIf set to true, requests made by widgets will always be proxied, same as setting useProxy: true on each widget. Note that this may break some widgets.
showSplashScreenbooleanOptionalIf set to true, a loading screen will be shown. Defaults to false.
enableErrorReportingbooleanOptionalEnable reporting of unexpected errors and crashes. This is off by default, and no data will ever be captured unless you explicitly enable it. Turning on error reporting helps previously unknown bugs get discovered and fixed. Dashy uses Sentry for error reporting. Defaults to false.
sentryDsnbooleanOptionalIf you need to monitor errors in your instance, then you can use Sentry to collect and process bug reports. Sentry can be self-hosted, or used as SaaS, once your instance is setup, then all you need to do is pass in the DSN here, and enable error reporting. You can learn more on the Sentry DSN Docs. Note that this will only ever be used if enableErrorReporting is explicitly enabled.
disableSmartSortbooleanOptionalFor the most-used and last-used app sort functions to work, a basic open-count is stored in local storage. If you do not want this to happen, then disable smart sort here, but you wil no longer be able to use these sort options. Defaults to false.
disableUpdateChecksbooleanOptionalIf set to true, Dashy will not check for updates. Defaults to false.
enableServiceWorkerbooleanOptionalService workers cache web applications to improve load times and offer basic offline functionality, and are enabled by default in Dashy. The service worker can sometimes cause older content to be cached, requiring the app to be hard-refreshed. If you do not want SW functionality, or are having issues with caching, set this property to false to disable all service workers.
disableContextMenubooleanOptionalIf set to true, the custom right-click context menu will be disabled. Defaults to false.

⬆️ Back to Top

appConfig.auth (optional)#

FieldTypeRequiredDescription
usersarrayOptionalAn array of objects containing usernames and hashed passwords. If this is not provided, then authentication will be off by default, and you will not need any credentials to access the app. See appConfig.auth.users.
Note this method of authentication is handled on the client side, so for security critical situations, it is recommended to use an alternate authentication method.
enableKeycloakbooleanOptionalIf set to true, then authentication using Keycloak will be enabled. Note that you need to have an instance running, and have also configured auth.keycloak. Defaults to false
keycloakobjectOptionalConfig options to point Dashy to your Keycloak server. Requires enableKeycloak: true. See auth.keycloak for more info
enableGuestAccessbooleanOptionalWhen set to true, an unauthenticated user will be able to access the dashboard, with read-only access, without having to login. Requires auth.users to be configured. Defaults to false.

For more info, see the Authentication Docs

⬆️ Back to Top

appConfig.auth.users (optional)#

FieldTypeRequiredDescription
userstringRequiredUsername to log in with
hashstringRequiredA SHA-256 hashed password
typestringOptionalThe user type, either admin or normal

⬆️ Back to Top

appConfig.auth.keycloak (optional)#

FieldTypeRequiredDescription
serverUrlstringRequiredThe URL (or URL/ IP + Port) where your keycloak server is running
realmstringRequiredThe name of the realm (must already be created) that you want to use
clientIdstringRequiredThe Client ID of the client you created for use with Dashy
legacySupportbooleanOptionalIf using Keycloak 17 or older, then set this to true

⬆️ Back to Top

appConfig.webSearch (optional)#

FieldTypeRequiredDescription
disableWebSearchstringOptionalWeb search is enabled by default, but can be disabled by setting this property to true
searchEnginestringOptionalSet the key name for your search engine. Can also use a custom engine by setting this property to custom. Currently supported: duckduckgo, google, whoogle, qwant, startpage, searx-bar and searx-info. Defaults to duckduckgo
customSearchEnginestringOptionalYou can also use a custom search engine, or your own self-hosted instance. This requires searchEngine: custom to be set. Then add the URL of your service, with GET query string included here
openingMethodstringOptionalSet your preferred opening method for search results: newtab, sametab, workspace. Defaults to newtab
searchBangsobjectOptionalA key-value-pair set of custom search bangs for redirecting query to a specific app or search engine. The key of each should be the bang you will type (typically starting with /, ! or :), and value is the destination, either as a search engine key (e.g. reddit) or a URL with search parameters (e.g. https://en.wikipedia.org/w/?search=)

⬆️ Back to Top

appConfig.hideComponents (optional)#

FieldTypeRequiredDescription
hideHeadingbooleanOptionalIf set to true, the page title & sub-title will not be visible. Defaults to false
hideNavbooleanOptionalIf set to true, the navigation menu will not be visible. Defaults to false
hideSearchbooleanOptionalIf set to true, the search bar will not be visible. Defaults to false
hideSettingsbooleanOptionalIf set to true, the settings menu will be initially collapsed. Defaults to false
hideFooterbooleanOptionalIf set to true, the footer will not be visible. Defaults to false

⬆️ Back to Top

section#

FieldTypeRequiredDescription
namestringRequiredThe title for the section
iconstringOptionalAn single icon to be displayed next to the title. See section.icon
itemsarrayOptionalAn array of items to be displayed within the section. See item. Sections must include either 1 or more items, or 1 or more widgets.
widgetsarrayOptionalAn array of widgets to be displayed within the section. See widget
displayDataobjectOptionalMeta-data to optionally override display settings for a given section. See displayData

⬆️ Back to Top

section.item#

FieldTypeRequiredDescription
titlestringRequiredThe text to display/ title of a given item. Max length 18
descriptionstringOptionalAdditional info about an item, which is shown in the tooltip on hover, or visible on large tiles
urlstringRequiredThe URL / location of web address for when the item is clicked
iconstringOptionalThe icon for a given item. Can be a font-awesome icon, favicon, remote URL or local URL. See item.icon
targetstringOptionalThe opening method for when the item is clicked, either newtab, sametab, modal, workspace, clipboard, top or parent. Where newtab will open the link in a new tab, sametab will open it in the current tab, and modal will open a pop-up modal, workspace will open in the Workspace view and clipboard will copy the URL to system clipboard (but not launch app). Defaults to newtab
hotkeynumberOptionalGive frequently opened applications a numeric hotkey, between 0 - 9. You can then just press that key to launch that application.
tagsstring[]OptionalA list of tags, which can be used for improved search
statusCheckbooleanOptionalWhen set to true, Dashy will ping the URL associated with the current service, and display its status as a dot next to the item. The value here will override appConfig.statusCheck so you can turn off or on checks for a given service. Defaults to appConfig.statusCheck, falls back to false
statusCheckUrlstringOptionalIf you've enabled statusCheck, and want to use a different URL to what is defined under the item, then specify it here
statusCheckHeadersobjectOptionalIf you're endpoint requires any specific headers for the status checking, then define them here
statusCheckAllowInsecurebooleanOptionalBy default, any request to insecure content will be blocked. Setting this option to true will disable the rejectUnauthorized option, enabling you to ping non-HTTPS services for the current item. Defaults to false
statusCheckAcceptCodesstringOptionalIf your service's response code is anything other than 2xx, then you can opt to specify an alternative success code. E.g. if you expect your server to return 403, but still want the status indicator to be green, set this value to 403
statusCheckMaxRedirectsnumberOptionalIf your service redirects to another page, and you would like status checks to follow redirects, then specify the maximum number of redirects here. Defaults to 0 / will not follow redirects
colorstringOptionalAn optional color for the text and font-awesome icon to be displayed in. Note that this will override the current theme and so may not display well
relstringOptionalThe value of the rel attribute for the link. Useful for specifying the relationship between the target link/document and Dashy. Defaults to noopener noreferrer
backgroundColorstringOptionalAn optional background fill color for the that given item. Again, this will override the current theme and so might not display well against the background
providerstringOptionalThe name of the provider for a given service, useful for when including hosted apps. In some themes, this is visible under the item name
displayDataobjectOptionalMeta-data to optionally override display settings for a given item. See displayData

⬆️ Back to Top

item.displayData (optional)#

FieldTypeRequiredDescription
hideForUsersstring[]OptionalCurrent item will be visible to all users, except for those specified in this list
showForUsersstring[]OptionalCurrent item will be hidden from all users, except for those specified in this list
hideForGuestsbooleanOptionalCurrent item will be visible for logged in users, but not for guests (see appConfig.enableGuestAccess). Defaults to false
hideForKeycloakUsersobjectOptionalCurrent item will be visible to all keycloak users, except for those configured via these groups and roles. See hideForKeycloakUsers
showForKeycloakUsersobjectOptionalCurrent item will be hidden from all keycloak users, except for those configured via these groups and roles. See showForKeycloakUsers

⬆️ Back to Top

section.widgets (optional)#

FieldTypeRequiredDescription
typestringRequiredThe widget type. See Widget Docs for full list of supported widgets
optionsobjectOptionalSome widgets accept either optional or required additional options. Again, see the Widget Docs for full list of options
updateIntervalnumberOptionalYou can keep a widget constantly updated by specifying an update interval, in seconds. See Continuous Updates Docs for more info
useProxybooleanOptionalSome widgets make API requests to services that are not CORS-enabled. For these instances, you will need to route requests through a proxy, Dashy has a built in CORS-proxy, which you can use by setting this option to true. Defaults to false. See the Proxying Requests Docs for more info
timeoutnumberOptionalRequest timeout in milliseconds, defaults to ½ a second (500)
ignoreErrorsbooleanOptionalPrevent an error message being displayed, if a network request or something else fails. Useful for false-positives
labelstringOptionalAdd custom label to a given widget. Useful for identification, if there are multiple of the same type of widget in a single section

⬆️ Back to Top

section.displayData (optional)#

FieldTypeRequiredDescription
sortBystringOptionalThe sort order for items within the current section. By default items are displayed in the order in which they are listed in within the config. The following sort options are supported: most-used (most opened apps first), last-used (the most recently used apps), alphabetical, reverse-alphabetical, random and default
collapsedbooleanOptionalIf true, the section will be collapsed initially, and will need to be clicked to open. Useful for less regularly used, or very long sections. Defaults to false
cutToHeightbooleanOptionalBy default, sections will fill available space. Set this option to true to match section height with content height
rowsnumberOptionalHeight of the section, specified as the number of rows it should span vertically, e.g. 2. Defaults to 1. Max is 5.
colsnumberOptionalWidth of the section, specified as the number of columns the section should span horizontally, e.g. 2. Defaults to 1. Max is 5.
itemSizestringOptionalSpecify the size for items within this group, either small, medium or large. Note that this will override any settings specified through the UI
colorstringOptionalA custom accent color for the section, as a hex code or HTML color (e.g. #fff)
customStylesstringOptionalCustom CSS properties that should be applied to that section, e.g. border: 2px dashed #ff0000;
sectionLayoutstringOptionalSpecify which CSS layout will be used to responsively place items. Can be either auto (which uses flex layout), or grid. If grid is selected, then itemCountX and itemCountY may also be set. Defaults to auto
itemCountXnumberOptionalThe number of items to display per row / horizontally. If not set, it will be calculated automatically based on available space. Can only be set if sectionLayout is set to grid. Must be a whole number between 1 and 12
itemCountYnumberOptionalThe number of items to display per column / vertically. If not set, it will be calculated automatically based on available space. If itemCountX is set, then itemCountY can be calculated automatically. Can only be set if sectionLayout is set to grid. Must be a whole number between 1 and 12
hideForUsersstring[]OptionalCurrent section will be visible to all users, except for those specified in this list
showForUsersstring[]OptionalCurrent section will be hidden from all users, except for those specified in this list
hideForGuestsbooleanOptionalCurrent section will be visible for logged in users, but not for guests (see appConfig.enableGuestAccess). Defaults to false
hideForKeycloakUsersobjectOptionalCurrent section will be visible to all keycloak users, except for those configured via these groups and roles. See hideForKeycloakUsers
showForKeycloakUsersobjectOptionalCurrent section will be hidden from all keycloak users, except for those configured via these groups and roles. See showForKeycloakUsers

⬆️ Back to Top

section.icon and section.item.icon#

FieldTypeRequiredDescription
iconstringOptionalThe icon for a given item or section.
See Icon Docs for all available supported icon types, including: auto-fetched favicons, generative icons, emoji icons, home-lab service logos, font-awesome, simple-icons, material icons, and icons specified by URL

⬆️ Back to Top

section.displayData.hideForKeycloakUsers, section.displayData.showForKeycloakUsers, item.displayData.hideForKeycloakUsers and item.displayData.showForKeycloakUsers#

FieldTypeRequiredDescription
groupsstring[]OptionalCurrent Section or Item will be hidden or shown based on the user having any of the groups in this list
rolesstring[]OptionalCurrent Section or Item will be hidden or shown based on the user having any of the roles in this list

⬆️ Back to Top


Notes#

Editing Config through the UI#

Config can be modified directly through the UI, and then written to disk, or applied locally. This can be done wither with the raw config editor (introduced in V 0.6.5 / #3), or the interactive editor (introduced in V 1.8.9 / #298).

Interactive Editor
Interactive Editor demo

JSON Editor
Config Editor demo

About YAML#

If you're new to YAML, it's pretty straight-forward. The format is exactly the same as that of JSON, but instead of using curly braces, structure is denoted using whitespace. This quick guide should get you up to speed in a few minutes, for more advanced topics take a look at this Wikipedia article.

Config Saving Methods#

When updating the config through the JSON editor in the UI, you have two save options: Local or Write to Disk.

  • Changes saved locally will only be applied to the current user through the browser, and will not apply to other instances - you either need to use the cloud sync feature, or manually update the conf.yml file.
  • On the other-hand, if you choose to write changes to disk, then your main conf.yml file will be updated, and changes will be applied to all users, and visible across all devices. For this functionality to work, you must be running Dashy with using the Docker container, or the Node server. A backup of your current configuration will also be saved in the same directory.

Preventing Changes#

If you have authentication set up, then any user who is not an admin (with type: admin) will not be able to write changes to disk.

You can also prevent changes from any user being written to disk, using preventWriteToDisk. Or prevent any changes from being saved locally in browser storage, using preventLocalSave.

To disable all UI config features, set disableConfiguration. Alternatively you can disable UI config features for all non Admin users by setting disableConfigurationForNonAdmin to true.

Example#

---pageInfo:  title: Home Labsections: # An array of sections- name: Section 1 - Getting Started  items: # An array of items  - title: GitHub    description: Source code and documentation on GitHub    icon: fab fa-github    url: https://github.com/Lissy93/dashy  - title: Issues    description: View currently open issues, or raise a new one    icon: fas fa-bug    url: https://github.com/Lissy93/dashy/issues  - title: Demo    description: A live demo    icon: far fa-rocket    url: https://dashy-demo-1.netlify.app- name: Section 2 - Local Services  items:  - title: Firewall    icon: favicon    url: http://192.168.1.1/  - title: Game Server    icon: https://i.ibb.co/710B3Yc/space-invader-x256.png    url: http://192.168.130.1/

For more example config files, see: this gist

If you need any help, feel free to Raise an Issue or Start a Discussion

Happy Configuring 🤓🔧

⬆️ Back to Top

- +

Configuring

All app configuration is specified in /public/conf.yml which is in YAML Format format. If you're using Docker, this file can be passed in as a volume. Changes can either be made directly to this file, or done through the UI. From the UI you can also export, backup, reset, validate and download your configuration file.

There are three ways to edit the config#

  • Directly in the YAML file (5/5 reliability, 3/5 usability)
    • Write changes directly to the conf.yml file, optionally using one of the templates provided. This can be done in your favorite editor and uploading to your server, or directly editing the file via SSH, but the easiest method would be to use Code Server
  • UI JSON Editor (4/5 reliability, 4/5 usability)
    • From the UI, under the config menu there is a JSON editor, with built-in validation, documentation and advanced options
  • UI Visual Editor (3/5 reliability, 5/5 usability)
    • From the UI, enter the Interactive Edit Mode, then click any part of the page to edit. Changes are previewed live, and then saved to disk
  • REST API (Coming soon)
    • Programmatically edit config either through the command line, using a script or a third-party application

Tips#

  • You may find it helpful to look at some sample config files to get you started, a collection of which can be found here
  • You can check that your config file fits the schema, by running yarn validate-config
  • After modifying your config, the app needs to be recompiled, by running yarn build - this happens automatically if you're using Docker
  • It is recommended to keep a backup of your config file. You can download it under Config menu, or use the Cloud Backup feature.
  • You can make use of YAML features, like anchors, comments, multi-line strings, etc to reuse attributes and keep your config file readable
  • Once you have finished configuring your dashboard, you can choose to disable UI config if you wish
  • All fields are optional, unless otherwise stated.

The following file provides a reference of all supported configuration options.

Contents#


Top-Level Fields#

FieldTypeRequiredDescription
pageInfoobjectRequiredBasic meta data like title, description, nav bar links, footer text. See pageInfo
appConfigobjectOptionalSettings related to how the app functions, including API keys and global styles. See appConfig
sectionsarrayRequiredAn array of sections, each containing an array of items, which will be displayed as links. See section
pagesarrayOptionalAn array additional config files, used for multi-page dashboards. See pages

⬆️ Back to Top

PageInfo#

FieldTypeRequiredDescription
titlestringRequiredYour dashboard title, displayed in the header and browser tab
descriptionstringOptionalDescription of your dashboard, also displayed as a subtitle
navLinksarrayOptionalOptional list of a maximum of 6 links, which will be displayed in the navigation bar. See navLinks
footerTextstringOptionalText to display in the footer (note that this will override the default footer content). This can also include HTML and inline CSS
logostringOptionalThe path to an image to display in the header (to the right of the title). This can be either local, where / is the root of ./public, or any remote image, such as https://i.ibb.co/yhbt6CY/dashy.png. It's recommended to scale your image down, so that it doesn't impact load times

⬆️ Back to Top

pageInfo.navLinks (optional)#

FieldTypeRequiredDescription
titlestringRequiredThe text to display on the link button
pathstringRequiredThe URL to navigate to when clicked. Can be relative (e.g. /about) or absolute (e.g. https://example.com or http://192.168.1.1)
targetstringOptionalThe opening method (external links only). Can be either newtab, sametab, top or parent. Defaults to newtab

⬆️ Back to Top

pages[] (optional)#

FieldTypeRequiredDescription
namestringRequiredA unique name for that page
pathstringRequiredThe path (local or remote) to the config file to use.
For files located within /public, you only need to specify filename, for externally hosted files you must include the full URL

⬆️ Back to Top

appConfig (optional)#

FieldTypeRequiredDescription
languagestringOptionalThe 2 (or 4-digit) ISO 639-1 code for your language, e.g. en or en-GB. This must be a language that the app has already been translated into. If your language is unavailable, Dashy will fallback to English. By default Dashy will attempt to auto-detect your language, although this may not work on some privacy browsers.
startingViewenumOptionalWhich page to load by default, and on the base page or domain root. You can still switch to different views from within the UI. Can be either default, minimal or workspace. Defaults to default
defaultOpeningMethodenumOptionalThe default opening method for items, if no target is specified for a given item. Can be either newtab, sametab, modal, workspace, clipboard, top or parent. Defaults to newtab
statusCheckbooleanOptionalWhen set to true, Dashy will ping each of your services and display their status as a dot next to each item. This can be overridden by setting statusCheck under each item. Defaults to false
statusCheckIntervalnumberOptionalThe number of seconds between checks. If set to 0 then service will only be checked on initial page load, which is usually the desired functionality. If value is less than 10 you may experience a hit in performance. Defaults to 0
webSearchobjectOptionalConfiguration options for the web search feature, set your default search engine, opening method or disable web search. See webSearch
backgroundImgstringOptionalPath to an optional full-screen app background image. This can be either remote (http) or local (relative to /app/public/item-icons/ inside the container). Note that this will slow down initial load
enableFontAwesomebooleanOptionalIf set to true font-awesome will be loaded, if set to false they will not be. if left blank font-awesome will be enabled only if required by 1 or more icons
enableMaterialDesignIconsbooleanOptionalIf set to true mdi icons will be loaded, if set to false they will not be. Where true is enabled, if left blank material design icons will be enabled only if required by 1 or more icons
fontAwesomeKeystringOptionalIf you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. 13014ae648)
faviconApienumOptionalOnly applicable if you are using favicons for item icons. Specifies which service to use to resolve favicons. Set to local to do this locally, without using an API. Services running locally will use this option always. Available options are: local, faviconkit, iconhorse, google, clearbit, webmasterapi and allesedv. Defaults to faviconkit. See Icons for more info
authobjectOptionalAll settings relating to user authentication. See auth
defaultIconstringOptionalAn icon to be applied to any items, which don't already have an icon set. See Icon Docs for more info
layoutenumOptionalLayout for homepage, either horizontal, vertical or auto. Defaults to auto. This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified and overridden from the UI.
iconSizeenumOptionalThe size of link items / icons. Can be either small, medium, or large. Defaults to medium. This can also be set directly from the UI.
colCountnumberOptionalThe number of columns of sections displayed on the homepage, using the default view. Should be in integer between 1 and 8. Note that by default this is applied responsively, based on current screen size, and specifying a value here will override this behavior, which may not be desirable.
themestringOptionalThe default theme for first load (you can change this later from the UI)
cssThemesstring[]OptionalAn array of custom theme names which can be used in the theme switcher dropdown
customColorsobjectOptionalEnables you to apply a custom color palette to any given theme. Use the theme name (lowercase) as the key, for an object including key-value-pairs, with the color variable name as keys, and 6-digit hex code as value. See Theming for more info
externalStyleSheetstring or string[]OptionalEither a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI
customCssstringOptionalRaw CSS that will be applied to the page. This can also be set from the UI. Please minify it first.
hideComponentsobjectOptionalA list of key page components (header, footer, search, settings, etc) that are present by default, but can be removed using this option. See appConfig.hideComponents
routingModestringOptionalCan be either hash or history. Determines the URL format for sub-pages, hash mode will look like /#/home whereas with history mode available you have nice clean URLs, like /home. For more info, see the Vue docs. If you're hosting Dashy with a custom BASE_URL, you will find that a bit of extra server config is necessary to get history mode working, so here you may want to instead use hash mode.Defaults to history.
enableMultiTaskingbooleanOptionalIf set to true, will keep apps open in the background when in the workspace view. Useful for quickly switching between multiple sites, and preserving their state, but comes at the cost of performance.
workspaceLandingUrlstringOptionalThe URL or an app, service or website to launch when the workspace view is opened, before another service has been launched
preventWriteToDiskbooleanOptionalIf set to true, users will be prevented from saving config changes to disk through the UI
preventLocalSavebooleanOptionalIf set to true, users will be prevented from applying config changes to local storage
disableConfigurationbooleanOptionalIf set to true, no users will be able to view or edit the config through the UI
disableConfigurationForNonAdminbooleanOptionalIf set to true, only admin users will be able to view or edit the config through the UI. disableConfiguration must not be set to true.
widgetsAlwaysUseProxybooleanOptionalIf set to true, requests made by widgets will always be proxied, same as setting useProxy: true on each widget. Note that this may break some widgets.
showSplashScreenbooleanOptionalIf set to true, a loading screen will be shown. Defaults to false.
enableErrorReportingbooleanOptionalEnable reporting of unexpected errors and crashes. This is off by default, and no data will ever be captured unless you explicitly enable it. Turning on error reporting helps previously unknown bugs get discovered and fixed. Dashy uses Sentry for error reporting. Defaults to false.
sentryDsnbooleanOptionalIf you need to monitor errors in your instance, then you can use Sentry to collect and process bug reports. Sentry can be self-hosted, or used as SaaS, once your instance is setup, then all you need to do is pass in the DSN here, and enable error reporting. You can learn more on the Sentry DSN Docs. Note that this will only ever be used if enableErrorReporting is explicitly enabled.
disableSmartSortbooleanOptionalFor the most-used and last-used app sort functions to work, a basic open-count is stored in local storage. If you do not want this to happen, then disable smart sort here, but you wil no longer be able to use these sort options. Defaults to false.
disableUpdateChecksbooleanOptionalIf set to true, Dashy will not check for updates. Defaults to false.
enableServiceWorkerbooleanOptionalService workers cache web applications to improve load times and offer basic offline functionality, and are enabled by default in Dashy. The service worker can sometimes cause older content to be cached, requiring the app to be hard-refreshed. If you do not want SW functionality, or are having issues with caching, set this property to false to disable all service workers.
disableContextMenubooleanOptionalIf set to true, the custom right-click context menu will be disabled. Defaults to false.

⬆️ Back to Top

appConfig.auth (optional)#

FieldTypeRequiredDescription
usersarrayOptionalAn array of objects containing usernames and hashed passwords. If this is not provided, then authentication will be off by default, and you will not need any credentials to access the app. See appConfig.auth.users.
Note this method of authentication is handled on the client side, so for security critical situations, it is recommended to use an alternate authentication method.
enableKeycloakbooleanOptionalIf set to true, then authentication using Keycloak will be enabled. Note that you need to have an instance running, and have also configured auth.keycloak. Defaults to false
keycloakobjectOptionalConfig options to point Dashy to your Keycloak server. Requires enableKeycloak: true. See auth.keycloak for more info
enableGuestAccessbooleanOptionalWhen set to true, an unauthenticated user will be able to access the dashboard, with read-only access, without having to login. Requires auth.users to be configured. Defaults to false.

For more info, see the Authentication Docs

⬆️ Back to Top

appConfig.auth.users (optional)#

FieldTypeRequiredDescription
userstringRequiredUsername to log in with
hashstringRequiredA SHA-256 hashed password
typestringOptionalThe user type, either admin or normal

⬆️ Back to Top

appConfig.auth.keycloak (optional)#

FieldTypeRequiredDescription
serverUrlstringRequiredThe URL (or URL/ IP + Port) where your keycloak server is running
realmstringRequiredThe name of the realm (must already be created) that you want to use
clientIdstringRequiredThe Client ID of the client you created for use with Dashy
legacySupportbooleanOptionalIf using Keycloak 17 or older, then set this to true

⬆️ Back to Top

appConfig.webSearch (optional)#

FieldTypeRequiredDescription
disableWebSearchstringOptionalWeb search is enabled by default, but can be disabled by setting this property to true
searchEnginestringOptionalSet the key name for your search engine. Can also use a custom engine by setting this property to custom. Currently supported: duckduckgo, google, whoogle, qwant, startpage, searx-bar and searx-info. Defaults to duckduckgo
customSearchEnginestringOptionalYou can also use a custom search engine, or your own self-hosted instance. This requires searchEngine: custom to be set. Then add the URL of your service, with GET query string included here
openingMethodstringOptionalSet your preferred opening method for search results: newtab, sametab, workspace. Defaults to newtab
searchBangsobjectOptionalA key-value-pair set of custom search bangs for redirecting query to a specific app or search engine. The key of each should be the bang you will type (typically starting with /, ! or :), and value is the destination, either as a search engine key (e.g. reddit) or a URL with search parameters (e.g. https://en.wikipedia.org/w/?search=)

⬆️ Back to Top

appConfig.hideComponents (optional)#

FieldTypeRequiredDescription
hideHeadingbooleanOptionalIf set to true, the page title & sub-title will not be visible. Defaults to false
hideNavbooleanOptionalIf set to true, the navigation menu will not be visible. Defaults to false
hideSearchbooleanOptionalIf set to true, the search bar will not be visible. Defaults to false
hideSettingsbooleanOptionalIf set to true, the settings menu will be initially collapsed. Defaults to false
hideFooterbooleanOptionalIf set to true, the footer will not be visible. Defaults to false

⬆️ Back to Top

section#

FieldTypeRequiredDescription
namestringRequiredThe title for the section
iconstringOptionalAn single icon to be displayed next to the title. See section.icon
itemsarrayOptionalAn array of items to be displayed within the section. See item. Sections must include either 1 or more items, or 1 or more widgets.
widgetsarrayOptionalAn array of widgets to be displayed within the section. See widget
displayDataobjectOptionalMeta-data to optionally override display settings for a given section. See displayData

⬆️ Back to Top

section.item#

FieldTypeRequiredDescription
titlestringRequiredThe text to display/ title of a given item. Max length 18
descriptionstringOptionalAdditional info about an item, which is shown in the tooltip on hover, or visible on large tiles
urlstringRequiredThe URL / location of web address for when the item is clicked
iconstringOptionalThe icon for a given item. Can be a font-awesome icon, favicon, remote URL or local URL. See item.icon
targetstringOptionalThe opening method for when the item is clicked, either newtab, sametab, modal, workspace, clipboard, top or parent. Where newtab will open the link in a new tab, sametab will open it in the current tab, and modal will open a pop-up modal, workspace will open in the Workspace view and clipboard will copy the URL to system clipboard (but not launch app). Defaults to newtab
hotkeynumberOptionalGive frequently opened applications a numeric hotkey, between 0 - 9. You can then just press that key to launch that application.
tagsstring[]OptionalA list of tags, which can be used for improved search
statusCheckbooleanOptionalWhen set to true, Dashy will ping the URL associated with the current service, and display its status as a dot next to the item. The value here will override appConfig.statusCheck so you can turn off or on checks for a given service. Defaults to appConfig.statusCheck, falls back to false
statusCheckUrlstringOptionalIf you've enabled statusCheck, and want to use a different URL to what is defined under the item, then specify it here
statusCheckHeadersobjectOptionalIf you're endpoint requires any specific headers for the status checking, then define them here
statusCheckAllowInsecurebooleanOptionalBy default, any request to insecure content will be blocked. Setting this option to true will disable the rejectUnauthorized option, enabling you to ping non-HTTPS services for the current item. Defaults to false
statusCheckAcceptCodesstringOptionalIf your service's response code is anything other than 2xx, then you can opt to specify an alternative success code. E.g. if you expect your server to return 403, but still want the status indicator to be green, set this value to 403
statusCheckMaxRedirectsnumberOptionalIf your service redirects to another page, and you would like status checks to follow redirects, then specify the maximum number of redirects here. Defaults to 0 / will not follow redirects
colorstringOptionalAn optional color for the text and font-awesome icon to be displayed in. Note that this will override the current theme and so may not display well
relstringOptionalThe value of the rel attribute for the link. Useful for specifying the relationship between the target link/document and Dashy. Defaults to noopener noreferrer
backgroundColorstringOptionalAn optional background fill color for the that given item. Again, this will override the current theme and so might not display well against the background
providerstringOptionalThe name of the provider for a given service, useful for when including hosted apps. In some themes, this is visible under the item name
displayDataobjectOptionalMeta-data to optionally override display settings for a given item. See displayData

⬆️ Back to Top

item.displayData (optional)#

FieldTypeRequiredDescription
hideForUsersstring[]OptionalCurrent item will be visible to all users, except for those specified in this list
showForUsersstring[]OptionalCurrent item will be hidden from all users, except for those specified in this list
hideForGuestsbooleanOptionalCurrent item will be visible for logged in users, but not for guests (see appConfig.enableGuestAccess). Defaults to false
hideForKeycloakUsersobjectOptionalCurrent item will be visible to all keycloak users, except for those configured via these groups and roles. See hideForKeycloakUsers
showForKeycloakUsersobjectOptionalCurrent item will be hidden from all keycloak users, except for those configured via these groups and roles. See showForKeycloakUsers

⬆️ Back to Top

section.widgets (optional)#

FieldTypeRequiredDescription
typestringRequiredThe widget type. See Widget Docs for full list of supported widgets
optionsobjectOptionalSome widgets accept either optional or required additional options. Again, see the Widget Docs for full list of options
updateIntervalnumberOptionalYou can keep a widget constantly updated by specifying an update interval, in seconds. See Continuous Updates Docs for more info
useProxybooleanOptionalSome widgets make API requests to services that are not CORS-enabled. For these instances, you will need to route requests through a proxy, Dashy has a built in CORS-proxy, which you can use by setting this option to true. Defaults to false. See the Proxying Requests Docs for more info
timeoutnumberOptionalRequest timeout in milliseconds, defaults to ½ a second (500)
ignoreErrorsbooleanOptionalPrevent an error message being displayed, if a network request or something else fails. Useful for false-positives
labelstringOptionalAdd custom label to a given widget. Useful for identification, if there are multiple of the same type of widget in a single section

⬆️ Back to Top

section.displayData (optional)#

FieldTypeRequiredDescription
sortBystringOptionalThe sort order for items within the current section. By default items are displayed in the order in which they are listed in within the config. The following sort options are supported: most-used (most opened apps first), last-used (the most recently used apps), alphabetical, reverse-alphabetical, random and default
collapsedbooleanOptionalIf true, the section will be collapsed initially, and will need to be clicked to open. Useful for less regularly used, or very long sections. Defaults to false
cutToHeightbooleanOptionalBy default, sections will fill available space. Set this option to true to match section height with content height
rowsnumberOptionalHeight of the section, specified as the number of rows it should span vertically, e.g. 2. Defaults to 1. Max is 5.
colsnumberOptionalWidth of the section, specified as the number of columns the section should span horizontally, e.g. 2. Defaults to 1. Max is 5.
itemSizestringOptionalSpecify the size for items within this group, either small, medium or large. Note that this will override any settings specified through the UI
colorstringOptionalA custom accent color for the section, as a hex code or HTML color (e.g. #fff)
customStylesstringOptionalCustom CSS properties that should be applied to that section, e.g. border: 2px dashed #ff0000;
sectionLayoutstringOptionalSpecify which CSS layout will be used to responsively place items. Can be either auto (which uses flex layout), or grid. If grid is selected, then itemCountX and itemCountY may also be set. Defaults to auto
itemCountXnumberOptionalThe number of items to display per row / horizontally. If not set, it will be calculated automatically based on available space. Can only be set if sectionLayout is set to grid. Must be a whole number between 1 and 12
itemCountYnumberOptionalThe number of items to display per column / vertically. If not set, it will be calculated automatically based on available space. If itemCountX is set, then itemCountY can be calculated automatically. Can only be set if sectionLayout is set to grid. Must be a whole number between 1 and 12
hideForUsersstring[]OptionalCurrent section will be visible to all users, except for those specified in this list
showForUsersstring[]OptionalCurrent section will be hidden from all users, except for those specified in this list
hideForGuestsbooleanOptionalCurrent section will be visible for logged in users, but not for guests (see appConfig.enableGuestAccess). Defaults to false
hideForKeycloakUsersobjectOptionalCurrent section will be visible to all keycloak users, except for those configured via these groups and roles. See hideForKeycloakUsers
showForKeycloakUsersobjectOptionalCurrent section will be hidden from all keycloak users, except for those configured via these groups and roles. See showForKeycloakUsers

⬆️ Back to Top

section.icon and section.item.icon#

FieldTypeRequiredDescription
iconstringOptionalThe icon for a given item or section.
See Icon Docs for all available supported icon types, including: auto-fetched favicons, generative icons, emoji icons, home-lab service logos, font-awesome, simple-icons, material icons, and icons specified by URL

⬆️ Back to Top

section.displayData.hideForKeycloakUsers, section.displayData.showForKeycloakUsers, item.displayData.hideForKeycloakUsers and item.displayData.showForKeycloakUsers#

FieldTypeRequiredDescription
groupsstring[]OptionalCurrent Section or Item will be hidden or shown based on the user having any of the groups in this list
rolesstring[]OptionalCurrent Section or Item will be hidden or shown based on the user having any of the roles in this list

⬆️ Back to Top


Notes#

Editing Config through the UI#

Config can be modified directly through the UI, and then written to disk, or applied locally. This can be done wither with the raw config editor (introduced in V 0.6.5 / #3), or the interactive editor (introduced in V 1.8.9 / #298).

Interactive Editor
Interactive Editor demo

JSON Editor
Config Editor demo

About YAML#

If you're new to YAML, it's pretty straight-forward. The format is exactly the same as that of JSON, but instead of using curly braces, structure is denoted using whitespace. This quick guide should get you up to speed in a few minutes, for more advanced topics take a look at this Wikipedia article.

Config Saving Methods#

When updating the config through the JSON editor in the UI, you have two save options: Local or Write to Disk.

  • Changes saved locally will only be applied to the current user through the browser, and will not apply to other instances - you either need to use the cloud sync feature, or manually update the conf.yml file.
  • On the other-hand, if you choose to write changes to disk, then your main conf.yml file will be updated, and changes will be applied to all users, and visible across all devices. For this functionality to work, you must be running Dashy with using the Docker container, or the Node server. A backup of your current configuration will also be saved in the same directory.

Preventing Changes#

If you have authentication set up, then any user who is not an admin (with type: admin) will not be able to write changes to disk.

You can also prevent changes from any user being written to disk, using preventWriteToDisk. Or prevent any changes from being saved locally in browser storage, using preventLocalSave.

To disable all UI config features, set disableConfiguration. Alternatively you can disable UI config features for all non Admin users by setting disableConfigurationForNonAdmin to true.

Example#

---pageInfo:  title: Home Labsections: # An array of sections- name: Section 1 - Getting Started  items: # An array of items  - title: GitHub    description: Source code and documentation on GitHub    icon: fab fa-github    url: https://github.com/Lissy93/dashy  - title: Issues    description: View currently open issues, or raise a new one    icon: fas fa-bug    url: https://github.com/Lissy93/dashy/issues  - title: Demo    description: A live demo    icon: far fa-rocket    url: https://dashy-demo-1.netlify.app- name: Section 2 - Local Services  items:  - title: Firewall    icon: favicon    url: http://192.168.1.1/  - title: Game Server    icon: https://i.ibb.co/710B3Yc/space-invader-x256.png    url: http://192.168.130.1/

For more example config files, see: this gist

If you need any help, feel free to Raise an Issue or Start a Discussion

Happy Configuring 🤓🔧

⬆️ Back to Top

+ \ No newline at end of file diff --git a/docs/contributing/index.html b/docs/contributing/index.html index d0cae185..aceda7a4 100644 --- a/docs/contributing/index.html +++ b/docs/contributing/index.html @@ -6,7 +6,7 @@ Contributing | Dashy - + @@ -34,8 +34,8 @@ All content is located either in the ./README.md< Alicia Sykes on Keybase Alicia Sykes's Website Alicia Sykes's Blog -Alicia Sykes's PGP

If you like, you could also consider subscribing to my mailing list for occasional blog post updates.


Contributors#

For a full list of Dashy's contributors, see the Credits Page

Auto-generated contributors

Star-Gazers Over Time#

Stargazers

- +Alicia Sykes's PGP

If you like, you could also consider subscribing to my mailing list for occasional blog post updates.


Contributors#

For a full list of Dashy's contributors, see the Credits Page

Auto-generated contributors

Star-Gazers Over Time#

Stargazers

+ \ No newline at end of file diff --git a/docs/credits/index.html b/docs/credits/index.html index 4cf97559..4f76f06b 100644 --- a/docs/credits/index.html +++ b/docs/credits/index.html @@ -6,13 +6,13 @@ Credits | Dashy - +
-

Credits

Sponsors#

koconder
Vincent Koc
peng1can
Null
alydemah
Aly Mohamed
bgadrian
B.G.Adrian
tbjers
Torgny Bjers
emlazzarin
Eddy Lazzarin
AnandChowdhary
Anand Chowdhary
shrippen
Null
bile0026
Zach Biles
UlisesGascon
Ulises Gascón
digitalarche
Digital Archeology
InDieTasten
Null
bmcgonag
Brian McGonagill
vlad-timofeev
Vlad Timofeev
helixzz
HeliXZz
forwardemail
Forward Email - Open-source & Privacy-focused Email Service (2023)
Bastii717
Null
frankdez93
Null
ratty222
Ratty222
hernanpopper
Null
NixyJuppie
Nixy
nrvo
Null
mezza93
Null

Contributors#

Lissy93
Alicia Sykes
liss-bot
Alicia Bot
marekful
Marcell Fülöp
EVOTk
EVOTk
snyk-bot
Snyk Bot
azerioxal
Kenneth Church
m42e
Matthias Bilger
pinarruiz
Alejandro Pinar Ruiz
CrazyWolf13
Tobias
kashif-se
Kashif Sohail
josuablejeru
Josua Blejeru
walkxcode
Walkx
evroon
Erik Vroon
jammo2k5
Jammo2k5
lordpansar
Magnus Sundström
Cereal916
Kristian Brasel
albcp
Alberto
altearius
Chris Nielsen
UrekD
UrekD
wozboz
Null
Totto16
Totto16
remygrandin
Remygrandin
DimitriDR
Dimitri
Tracreed
David Alasow
aviolaris
Andreas Violaris
rubenandre
Rúben Silva
rtm516
Rtm516
zcq100
Null
onedr0p
ᗪєνιη ᗷυнʟ
stanly0726
Stanly0726
Bogyie
Bogyeong Kim
Tuzi555
Jakub Tuzar
berksmbl
Berk Sümbül
alucarddelta
Brent
k073l
Null
kt-alt
Null
mmihaly
Null
patrickheeney
Patrick Heeney
rokiden
Denis Kazimirov
ssrangisetti
Null
BySempron
Sergio
itsmejoeeey
Joey Miller
hockeymikey
Null
thomaswienecke
Thomas Wienecke
deneor
Null
daentech
Dan Gilbert
moemoeq
CHAIYEON CHO
BOZG
Stephen Rigney
a-mnich
Alexander Mnich
alayham
Al-Ayham Saleh
alexdelprete
Alessandro Del Prete
sachahjkl
Sacha
shazzx
Shazz
ThinkSalat
Shawn Salat
royshreyaa
Null
Smexhy
Null
stavros-k
Stavros Kois
XenonR
Steffen Schmidt
StevKast
Steven Kast
AmadeusGraves
Ángel Fernández Sánchez
turnrye
Ryan Turner
rubjo
Null
PrynsTag
Prince Carl Velasco
PlusaN
Andrey
oka4shi
OKAMOTO Shigehiro
bubylou
Nicholas Malcolm
miclav
Michael Lavaire
imsakg
Mert Sefa AKGUN
ethan-hann
Ethan Hann
tazboyz16
Null
sur1v
José Ignacio
soaibsafi
Soaibuzzaman
pablomalo
Null
markxoe
Mark Oude Elberink
lxjv
Laker Turner
kxenoxx
Kxenox
jrobles98
Null
jnach
Jnach
imlonghao
Imlonghao
icy-comet
Aniket Teredesai
huangshaohuai
Null
flechaig
Null
dr460nf1r3
Nico
baifengheixi
Null
allozavrr
Null
XertDev
Xert
emiran-orange
Null
edugof
Eduardo Gomez
Dylan-Bs
Dylan Bersans
dougaldhub
Doug Lock
dkyeremeh
Desmond Kyeremeh
deepsourcebot
DeepSource Bot
DawidPietrykowski
Null
skaarj1989
David
clsty
Celestial.y
bskim45
Bumsoo Kim
BhasherBEL
Brieuc Dubois
BeginCI
Begin
BRAVO68WEB
Jyotirmoy Bandyopadhyaya [Bravo68]
AaronPorts
Artyom
alydemah
Aly Mohamed
5idereal
5idereal
0n1cOn3
0n1cOn3
maximemoreillon
Maxime Moreillon
Glitch3dPenguin
Max Kulik
markusdd
Markus Krause
asenov
Мирослав Асенов
luispabon
Luis Pabon
LeoColman
Leonardo Colman Lopes
KierenConnell
Kieren Connell
kieraneglin
Kieran
Singebob
Jeremy Chauvin
Hellhium
Jemy SCHNEPP
jjmung
JJ Munguia
b1thunt3r
Ishan Jain
Compunctus
Iaroslav Dronskii
nealian
Ian Neal
FraglyG
Hendrik Strydom
hubortje
Harald Töpfer
gbrown09
Garrett Brown
FormatToday
FormatToday

Helpful Users#

evotk
Evotk
shadowking001
LawrenceP.
urekd
Urekd
dylanbeme
DylanH
milesteg1
Milesteg1
lu4t
Lu4t

Bots#

liss-bot
Alicia Bot
snyk-bot
Snyk Bot
netlify
Netlify
viezly
Viezly
muse-dev
MuseDev
github-actions[bot]
github-actions[bot]
dependabot[bot]
dependabot[bot]

The above section is auto-generated, using contribute-list by @akhilmhdh.

Newest Stargazers#

Recent Star Gazers

Recent Forkers


Dependencies#

This app definitely wouldn't have been quite so possible without the making use of the following package and components. Full credit and big kudos to their respective authors, who've done an amazing job in building and maintaining them. For a full breakdown of dependency licenses, please see Legal

Core#

At it's core, the application uses Vue.js, as well as it's services with VueX for state management. Styling is done with SCSS, JavaScript is currently Babel, (but I am in the process of converting to TypeScript). Linting is done with ESLint and Prettier, both following the AirBnB Styleguide. The config is defined in YAML, with a simple Node.js server to serve up the static app and the optional API endpoints, and container deployment is done with Docker.

Utilities#

  • crypto-js - Encryption implementations by @evanvosberg and community MIT
  • axios - Promise based HTTP client by @mzabriskie and community MIT
  • ajv - JSON schema Validator by @epoberezkin and community MIT
  • i18n - Internationalization plugin by @kazupon and community MIT
  • frappe-charts - Lightweight charting library by @frappe MIT

Frontend Components#

Backup & Sync Server#

Although the app is purely frontend, there is an optional cloud sync feature, for off-site backup and restore. This is built as a serverless function on Cloudflare workers using KV and web crypto

External Services#

The 1-Click deploy demo uses Play-with-Docker Labs. Code is hosted on GitHub, Docker images are hosted on DockerHub, and the demos are hosted on Netlify.

Actions#

This repo makes heavy use of GitHub actions to run automated workflows. The following base actions are totally awesome, and have been extremely useful. Full credit to their respective authors


You#

Would you like to be listed here? Whatever your skill set, Dashy needs people like you to help support future development. Check out the Contributing Page for ways that you can get involved. Huge thank you to everyone who has already contributed! 💖

- +

Credits

Sponsors#

koconder
Vincent Koc
peng1can
Null
alydemah
Aly Mohamed
bgadrian
B.G.Adrian
tbjers
Torgny Bjers
emlazzarin
Eddy Lazzarin
AnandChowdhary
Anand Chowdhary
shrippen
Null
bile0026
Zach Biles
UlisesGascon
Ulises Gascón
digitalarche
Digital Archeology
InDieTasten
Null
bmcgonag
Brian McGonagill
vlad-timofeev
Vlad Timofeev
helixzz
HeliXZz
mryesiller
Göksel Yeşiller
forwardemail
Forward Email - Open-source & Privacy-focused Email Service (2023)
Bastii717
Null
frankdez93
Null
ratty222
Ratty222
hernanpopper
Null
NixyJuppie
Nixy
nrvo
Null
mezza93
Null

Contributors#

Lissy93
Alicia Sykes
liss-bot
Alicia Bot
marekful
Marcell Fülöp
EVOTk
EVOTk
snyk-bot
Snyk Bot
azerioxal
Kenneth Church
m42e
Matthias Bilger
CrazyWolf13
Tobias
pinarruiz
Alejandro Pinar Ruiz
imjimmeh
Null
kashif-se
Kashif Sohail
walkxcode
Walkx
josuablejeru
Josua Blejeru
evroon
Erik Vroon
jammo2k5
Jammo2k5
lordpansar
Magnus Sundström
Cereal916
Kristian Brasel
albcp
Alberto
altearius
Chris Nielsen
UrekD
UrekD
wozboz
Null
Totto16
Totto16
remygrandin
Remygrandin
DimitriDR
Dimitri
Tracreed
David Alasow
aviolaris
Andreas Violaris
rubenandre
Rúben Silva
rtm516
Rtm516
zcq100
Null
onedr0p
ᗪєνιη ᗷυнʟ
stanly0726
Stanly0726
Bogyie
Bogyeong Kim
Tuzi555
Jakub Tuzar
berksmbl
Berk Sümbül
alucarddelta
Brent
k073l
Null
kt-alt
Null
mmihaly
Null
patrickheeney
Patrick Heeney
rokiden
Denis Kazimirov
ssrangisetti
Null
BySempron
Sergio
itsmejoeeey
Joey Miller
hockeymikey
Null
thomaswienecke
Thomas Wienecke
deneor
Null
daentech
Dan Gilbert
moemoeq
CHAIYEON CHO
BOZG
Stephen Rigney
a-mnich
Alexander Mnich
alayham
Al-Ayham Saleh
alexdelprete
Alessandro Del Prete
sachahjkl
Sacha
shazzx
Shazz
ThinkSalat
Shawn Salat
royshreyaa
Null
Smexhy
Null
stavros-k
Stavros Kois
XenonR
Steffen Schmidt
StevKast
Steven Kast
AmadeusGraves
Ángel Fernández Sánchez
turnrye
Ryan Turner
rubjo
Null
PrynsTag
Prince Carl Velasco
PlusaN
Andrey
oka4shi
OKAMOTO Shigehiro
bubylou
Nicholas Malcolm
miclav
Michael Lavaire
imsakg
Mert Sefa AKGUN
ethan-hann
Ethan Hann
tazboyz16
Null
sur1v
José Ignacio
soaibsafi
Soaibuzzaman
pablomalo
Null
markxoe
Mark Oude Elberink
lxjv
Laker Turner
kxenoxx
Kxenox
jrobles98
Null
jnach
Jnach
imlonghao
Imlonghao
icy-comet
Aniket Teredesai
huangshaohuai
Null
flechaig
Null
dr460nf1r3
Nico
baifengheixi
Null
allozavrr
Null
XertDev
Xert
emiran-orange
Null
edugof
Eduardo Gomez
Dylan-Bs
Dylan Bersans
dougaldhub
Doug Lock
dkyeremeh
Desmond Kyeremeh
deepsourcebot
DeepSource Bot
DawidPietrykowski
Null
skaarj1989
David
clsty
Celestial.y
bskim45
Bumsoo Kim
BhasherBEL
Brieuc Dubois
BeginCI
Begin
BRAVO68WEB
Jyotirmoy Bandyopadhyaya [Bravo68]
AaronPorts
Artyom
alydemah
Aly Mohamed
5idereal
5idereal
0n1cOn3
0n1cOn3
maximemoreillon
Maxime Moreillon
Glitch3dPenguin
Max Kulik
markusdd
Markus Krause
asenov
Мирослав Асенов
luispabon
Luis Pabon
LeoColman
Leonardo Colman Lopes
KierenConnell
Kieren Connell
kieraneglin
Kieran
Singebob
Jeremy Chauvin
Hellhium
Jemy SCHNEPP
jjmung
JJ Munguia
b1thunt3r
Ishan Jain
Compunctus
Iaroslav Dronskii
nealian
Ian Neal
FraglyG
Hendrik Strydom
hubortje
Harald Töpfer
gbrown09
Garrett Brown
FormatToday
FormatToday

Helpful Users#

evotk
Evotk
shadowking001
LawrenceP.
urekd
Urekd
dylanbeme
DylanH
milesteg1
Milesteg1
lu4t
Lu4t

Bots#

liss-bot
Alicia Bot
snyk-bot
Snyk Bot
netlify
Netlify
viezly
Viezly
muse-dev
MuseDev
github-actions[bot]
github-actions[bot]
dependabot[bot]
dependabot[bot]

The above section is auto-generated, using contribute-list by @akhilmhdh.

Newest Stargazers#

Recent Star Gazers

Recent Forkers


Dependencies#

This app definitely wouldn't have been quite so possible without the making use of the following package and components. Full credit and big kudos to their respective authors, who've done an amazing job in building and maintaining them. For a full breakdown of dependency licenses, please see Legal

Core#

At it's core, the application uses Vue.js, as well as it's services with VueX for state management. Styling is done with SCSS, JavaScript is currently Babel, (but I am in the process of converting to TypeScript). Linting is done with ESLint and Prettier, both following the AirBnB Styleguide. The config is defined in YAML, with a simple Node.js server to serve up the static app and the optional API endpoints, and container deployment is done with Docker.

Utilities#

  • crypto-js - Encryption implementations by @evanvosberg and community MIT
  • axios - Promise based HTTP client by @mzabriskie and community MIT
  • ajv - JSON schema Validator by @epoberezkin and community MIT
  • i18n - Internationalization plugin by @kazupon and community MIT
  • frappe-charts - Lightweight charting library by @frappe MIT

Frontend Components#

Backup & Sync Server#

Although the app is purely frontend, there is an optional cloud sync feature, for off-site backup and restore. This is built as a serverless function on Cloudflare workers using KV and web crypto

External Services#

The 1-Click deploy demo uses Play-with-Docker Labs. Code is hosted on GitHub, Docker images are hosted on DockerHub, and the demos are hosted on Netlify.

Actions#

This repo makes heavy use of GitHub actions to run automated workflows. The following base actions are totally awesome, and have been extremely useful. Full credit to their respective authors


You#

Would you like to be listed here? Whatever your skill set, Dashy needs people like you to help support future development. Check out the Contributing Page for ways that you can get involved. Huge thank you to everyone who has already contributed! 💖

+ \ No newline at end of file diff --git a/docs/deployment/index.html b/docs/deployment/index.html index e4e01a4e..ecd7c514 100644 --- a/docs/deployment/index.html +++ b/docs/deployment/index.html @@ -6,7 +6,7 @@ Deployment | Dashy - + @@ -15,7 +15,7 @@ Status: Docker Build StatusDocker PullsDocker StarsDocker Image SizeDocker Cloud Build

Dashy has a built container image hosted on Docker Hub. You will need Docker installed on your system.

docker run -d \  -p 8080:80 \  -v /root/my-local-conf.yml:/app/public/conf.yml \  --name my-dashboard \  --restart=always \  lissy93/dashy:latest

Explanation of the above options:

  • -d Detached mode (not running in the foreground of your terminal)
  • -p The port that should be exposed, and the port it should be mapped to in your host system [host-port][container-port], leave the container port as is
  • -v Specify volumes, to pass data from your host system to the container, in the format of [host-path]:[container-path], you can use this to pass your config file, directory of assets (like icons), custom CSS or web assets (like favicon.ico, manifest.json etc)
  • --name Give your container a human-readable name
  • --restart=always Spin up the container when the daemon starts, or after it has been stopped
  • lissy93/dashy:latest This last option is the image the container should be built from, you can also use a specific version or architecture type, by replacing :latest with one of the tags

For all available options, and to learn more, see the Docker Run Docs

Dashy is also available through GHCR: docker pull ghcr.io/lissy93/dashy:latest

If you're deploying Dashy on a modern ARM-based board, such as a Raspberry Pi (2+), then you'll need to use one of Dashy's ARM images. Set the base image + tag to either lissy93/dashy:arm64v8 or lissy93/dashy:arm32v7, depending on your system architecture. You can also use the multi-arch image, which should work on all system architectures.

The image defaults to :latest, but you can instead specify a specific version, e.g. docker pull lissy93/dashy:release-1.5.0


Using Docker Compose#

Using Docker Compose can be useful for saving your specific config in files, without having to type out a long run command each time. Save compose config as a YAML file, and then run docker compose up -d (optionally use the -f flag to specify file location, if it isn't located at ./docker-compose.yml), -d is detached mode (not running in the foreground of your terminal). Compose is also useful if you are using clusters, as the format is very similar to stack files, used with Docker Swarm.

The following is a complete example of a docker-compose.yml for Dashy. Run it as is, or uncomment the additional options you need.

---version: "3.8"services:  dashy:    # To build from source, replace 'image: lissy93/dashy' with 'build: .'    # build: .    image: lissy93/dashy    container_name: Dashy    # Pass in your config file below, by specifying the path on your host machine    # volumes:      # - /root/my-config.yml:/app/public/conf.yml    ports:      - 4000:80    # Set any environmental variables    environment:      - NODE_ENV=production    # Specify your user ID and group ID. You can find this by running `id -u` and `id -g`    #  - UID=1000    #  - GID=1000    # Specify restart policy    restart: unless-stopped    # Configure healthchecks    healthcheck:      test: ['CMD', 'node', '/app/services/healthcheck']      interval: 1m30s      timeout: 10s      retries: 3      start_period: 40s

You can use a different tag, by for example setting image: lissy93/dashy:arm64v8, or pull from GHCR instead by setting image: ghcr.io/lissy93/dashy.

If you are building from source, and would like to use one of the other Dockerfiles, then under services.dashy first set context: ., then specify the the path to the dockerfile, e.g. dockerfile: ./docker/Dockerfile-arm32v7


Kubernetes#

@vyrtualsynthese has written a Helm Chart for deploying with Kubernetes, available here


Unraid#

// TODO


Synology NAS#

Installing dashy is really simply and fast:

  1. Install Docker via Synology Package Center.

  2. Go to File Station and open the docker folder. Inside the docker folder, create one new folder and name it dashy.

    Note: Be careful to enter only lowercase, not uppercase letters.

  3. Go to Control Panel / Task Scheduler / Create / Scheduled Task / User-defined script.

  4. Once you click on User-defined script a new window will open.

  5. Follow the instructions below:

  6. General: In the Task field type in Install dashy. Uncheck "Enabled" option. Select root User.

  7. Schedule: Select Run on the following date then select "Do not repeat".

  8. Task Settings: Check "Send run details by email", add your email then copy paste the code below in the Run command area. After that click OK.

docker run -d \  -p 4000:80 \  -v /volume1/docker/dashy/my-local-conf.yml:/app/public/conf.yml \  --name dashy \  --restart=always \  lissy93/dashy:latest

dashy should be up within 1-2min after you've started the install task procedure


Build from Source#

If you do not want to use Docker, you can run Dashy directly on your host system. For this, you will need both git and the latest or LTS version of Node.js installed, and optionally yarn

  1. Get Code: git clone https://github.com/Lissy93/dashy.git and cd dashy
  2. Configuration: Fill in you're settings in ./public/conf.yml
  3. Install dependencies: yarn
  4. Build: yarn build
  5. Run: yarn start

Deploy to cloud service#

If you don't have a home server, then fear not - Dashy can be deployed to pretty much any cloud provider. The above Docker and NPM guides will work exactly the same on a VPS, but I've also setup some 1-Click deploy links for 10+ of the most common cloud providers, to make things easier. Note that if your instance is exposed to the internet, it will be your responsibility to adequately secure it.

Some hosting providers required a bit of extra configuration, which was why I've made separate branches for deploying to those services (named: deploy_cloudflare, deploy_digital-ocean, deploy_platform-sh and deploy_render). If there's another cloud service which you'd like 1-click deployment to be supported for, feel free to raise an issue.

[!NOTE] If you use a static hosting provider, then status checks, writing new config changes to disk from the UI, and triggering a rebuild through the UI will not be available. This is because these features need endpoints provided by Dashy's local Node server. Everything else should work just the same though.

Netlify#

Deploy to Netlify

Netlify offers Git-based serverless cloud hosting for web applications. Their services are free to use for personal use, and they support deployment from both public and private repos, as well as direct file upload. The free plan also allows you to use your own custom domain or sub-domain, and is easy to setup.

To deploy Dashy to Netlify, use the following link

https://app.netlify.com/start/deploy?repository=https://github.com/lissy93/dashy

Heroku#

Deploy to Heroku

Heroku is a fully managed cloud platform as a service. You define app settings in a Procfile and app.json, which specifying how the app should be build and how the server should be started. Heroku costs a minimum of $5 for 1,000 dyno hours per month (there are around 720 hours in a month), and supports custom domains. Heroku's single-dyno service is not as quite performant as some other providers, and the app will have a short wake-up time when not visited for a while

To deploy Dashy to Heroku, use the following link

https://heroku.com/deploy?template=https://github.com/Lissy93/dashy

Vercel#

Deploy with Vercel

Vercel is a performance-focused platform for hosting static frontend apps. It comes bundled with some useful tools for monitoring and analyzing application performance and other metrics. Vercel is free for personal use, allows for custom domains and has very reasonable limits.

To deploy Dashy to Vercel, use the following link

https://vercel.com/new/project?template=https://github.com/lissy93/dashy

DigitalOcean#

Deploy to DO

DigitalOcean is a cloud service providing affordable developer-friendly virtual machines from $5/month. But they also have an app platform, where you can run web apps, static sites, APIs and background workers. CDN-backed static sites are free for personal use.

https://cloud.digitalocean.com/apps/new?repo=https://github.com/lissy93/dashy/tree/deploy_digital-ocean

Google Cloud Platform#

Run on Google Cloud

Cloud Run is a service offered by Google Cloud. It's a fully managed serverless platform, for developing and deploying highly scalable containerized applications. Similar to AWS and Azure, GCP offers a wide range of cloud services, which are billed on a pay‐per‐use basis, but Cloud Run has a free tier offering 180,000 vCPU-seconds, 360,000 GiB-seconds, and 2 million requests per month.

To deploy Dashy to GCP, use the following link

https://deploy.cloud.run/?git_repo=https://github.com/lissy93/dashy.git

Platform.sh#

Deploy to Platform.sh

Platform.sh is an end-to-end solution for developing and deploying applications. It is geared towards enterprise users with large teams, and focuses on allowing applications to scale up and down. Unlike the above providers, Platform.sh is not free, although you can deploy a test app to it without needing a payment method

To deploy Dashy to Platform.sh, use the following link

https://console.platform.sh/projects/create-project/?template=https://github.com/lissy93/dashy

Render#

Deploy to Render

Render is cloud provider that provides easy deployments for static sites, Docker apps, web services, databases and background workers. Render is great for developing applications, and very easy to use. Static sites are free, and services start at $7/month. Currently there are only 2 server locations - Oregon, USA and Frankfurt, Germany. For more info, see the Render Docs

To deploy Dashy to Render, use the following link

https://render.com/deploy?repo=https://github.com/lissy93/dashy/tree/deploy_render

Railway#

Deploy on Railway

Railway is a Platform as a Service (PaaS) that offers a complete platform for building and delivering programs to the backend of the cloud. You bring your code and Railway does the rest. Railway offers an extremely good developer experience and makes it effortless to deploy apps. Railway offers a free Trial Plan, and paid plans start at $5/month. Railway has 4 server locations: US-west, US-east, EU-west and ASIA-South-East.

https://railway.app/template/MtdjAQ

Scalingo#

Deploy on Scalingo

Scalingo is a scalable container-based cloud platform as a service. It's focus is on compliance and uptime, and is geared towards enterprise users. Scalingo is also not free, although they do have a 3-day free trial that does not require a payment method.

To deploy Dashy to Scalingo, use the following link

https://my.scalingo.com/deploy?source=https://github.com/lissy93/dashy#master

Play-with-Docker#

Try in PWD

Play with Docker is a community project by Marcos Liljedhal and Jonathan Leibiusky and sponsored by Docker, intended to provide a hands-on learning environment. Their labs let you quickly spin up a Docker container or stack, and test out the image in a temporary, sandboxed environment. There's no need to sign up, and it's completely free.

To run Dashy in PWD, use the following URL:

https://labs.play-with-docker.com/?stack=https://raw.githubusercontent.com/Lissy93/dashy/master/docker-compose.yml

Surge.sh#

Follow instructions below

Surge.sh is quick and easy static web publishing platform for frontend-apps. Surge supports password-protected projects. You can also add a custom domain and then force HTTPS by default and optionally set a custom SSL certificate

To deploy Dashy to Surge.sh, first clone and cd into Dashy, install dependencies, and then use the following commands

yarn add -g surgeyarn buildsurge ./dist

Easypanel#

Deploy to Easypanel

Easypanel it's a modern server control panel. You can use it to deploy Dashy on your own server.

To deploy Dashy to Easypanel, use the following link

https://easypanel.io/docs/templates/dashy

Hosting with CDN#

Once Dashy has been built, it is effectively just a static web app. This means that it can be served up with pretty much any static host, CDN or web server. To host Dashy through a CDN, the steps are very similar to building from source: clone the project, cd into it, install dependencies, write your config file and build the app. Once build is complete you will have a ./dist directory within Dashy's root, and this is the build application which is ready to be served up.

However without Dashy's node server, there are a couple of features that will be unavailable to you, including: Writing config changes to disk through the UI, triggering a rebuild through the UI and application status checks. Everything else will work fine.


Requirements#

System Requirements#

Dashy works well on a Raspberry Pi (tested on Pi 3 and later), but should also run well on any system.

Docker#

Initial app build causes a spike in resource usage, but once the built app is running it is fairly steady. For this reason, Dashy works best with a minimum of 1GB of memory, and 1GB of disk space.

Bare Metal#

Minimum 526mb mem, 2GB disk space.

CDN / Cloud Deploy#

No specific requirements. The built application alone (without the Node server) is very light-weight, and can be handled smoothly by pretty much any CDN or cloud deployment service (see this list or natively supported cloud providers).

If you're using your own icons, or other assets, additional disk space will be required for those resources.

Browser Support#

JavaScript is required to run Dashy.

In terms of browser support, pretty much any browser released since 2018 should render content just fine. However, for Internet Explorer, only IE11+ is supported, yet performance here is still not optimal. The recommended browser is either a Chromium-based / Webkit browser (Chrome, Brave, Vivaldi, Edge, Yandex, etc), or Firefox or one of it's forks (FF-ESR, Tor, LibreWolf, etc). Recent versions of Safari and Opera are also supported, but with limited continuous testing.

- + \ No newline at end of file diff --git a/docs/developing/index.html b/docs/developing/index.html index 6a885a7c..5704f0d3 100644 --- a/docs/developing/index.html +++ b/docs/developing/index.html @@ -6,7 +6,7 @@ Developing | Dashy - + @@ -14,7 +14,7 @@

Developing

This article outlines how to get Dashy running in a development environment, and outlines the basics of the architecture. If you're adding new features, you may want to check out the Development Guides docs, for tutorials covering basic tasks.

Setting up the Dev Environment#

Prerequisites#

You will need either the latest or LTS version of Node.js to build and serve the application and Git to easily fetch the code, and push any changes. If you plan on running or deploying the container, you'll also need Docker. To avoid any unexpected issues, ensure you've got at least NPM V 7.5 or Yarn 1.22 (you may find NVM helpful for switching/ managing versions).

Running the Project#

  1. Get Code: git clone https://github.com/Lissy93/dashy.git
  2. Navigate into the directory: cd dashy
  3. Install dependencies: yarn
  4. Start dev server: yarn dev

Dashy should now be being served on http://localhost:8080/. Hot reload is enabled, so making changes to any of the files will trigger them to be rebuilt and the page refreshed.

Project Commands#

Basics#

  • yarn build - In the interest of speed, the application is pre-compiled, this means that the config file is read during build-time, and therefore the app needs to rebuilt for any new changes to take effect. Luckily this is very straight forward. Just run yarn build or docker exec -it [container-id] yarn build
  • yarn start - Starts a web server, and serves up the production site from ./dist (must run build command first)

Development#

  • yarn dev - Starts the development server with hot reloading
  • yarn lint - Lints code to ensure it follows a consistent, neat style
  • yarn test - Runs tests, and outputs results

Utils and Checks#

  • yarn validate-config - If you have quite a long configuration file, you may wish to check that it's all good to go, before deploying the app. This can be done with yarn validate-config or docker exec -it [container-id] yarn validate-config. Your config file needs to be in /public/conf.yml (or within your Docker container at /app/public/conf.yml). This will first check that your YAML is valid, and then validates it against Dashy's schema.
  • yarn health-check - Checks that the application is up and running on it's specified port, and outputs current status and response times. Useful for integrating into your monitoring service, if you need to maintain high system availability

Alternate Start Commands#

  • yarn build-and-start - Builds the app, runs checks and starts the production server. Commands are run in parallel, and so is faster than running them in independently. Uses the yarn build and yarn start commands
  • yarn build-watch - If you find yourself making frequent changes to your configuration, and do not want to have to keep manually rebuilding, then this option is for you. It will watch for changes to any files within the projects root, and then trigger a rebuild. Note that if you are developing new features, then yarn dev would be more appropriate, as it's significantly faster at recompiling (under 1 second), and has hot reloading, linting and testing integrated
  • yarn pm2-start - Starts the Node server using PM2, a process manager for Node.js applications, that helps them stay alive. PM2 has some built-in basic monitoring features, and an optional management solution. If you are running the app on bare metal, it is recommended to use this start command

Notes#

  • If you are using NPM, replace yarn with npm run
  • If you are using Docker, precede each command with docker exec -it [container-id]. Container ID can be found by running docker ps
  • You can manage the app using the Vue-CLI Service, with npx vue-cli-service [command]. Or to start the Vue Management UI, run npx vue ui, and open http://localhost:8000

Environmental Variables#

All environmental variables are optional. Currently there are not many environmental variables used, as most of the user preferences are stored under appConfig in the conf.yml file.

You can set variables either in your environment, or using the .env file.

  • NODE_ENV - Current environment, can be either development, production or test
  • PORT - The port to expose the running application on
  • HOST - The host that Dashy is running on, domain or IP
  • BASE_URL - The default base path for serving up static assets
  • VUE_APP_DOMAIN - Usually the same as BASE_URL, but accessible in frontend
  • INTEGRITY - Should enable SRI for build script and link resources
  • IS_DOCKER - Computed automatically on build. Indicates if running in container
  • VUE_APP_VERSION - Again, set automatically using package.json during build time
  • BACKUP_DIR - Directory for conf.yml backups

Environment Modes#

You can set the environment using the NODE_ENV variable. By default, the correct environment should be selected based on the script you run to start the app. The following environments are supported: production, development and test. For more info, see Vue CLI Environment Modes.


Git Strategy#

Git Flow#

Like most Git repos, we are following the Github Flow standard.

  1. Create a branch (or fork if you don'd have write access)
  2. Code some awesome stuff 🧑‍💻
  3. Add, commit and push your changes to your branch/ fork
  4. Head over to GitHub and create a Pull Request
  5. Fill in the required sections in the template, and hit submit
  6. Follow up with any reviews on your code
  7. Merge 🎉

Git Branch Naming#

The format of your branch name should be something similar to: [TYPE]/[TICKET]_[TITLE] For example, FEATURE/420_Awesome-feature or FIX/690_login-server-error

Commit Emojis#

Using a single emoji at the start of each commit message, to indicate the type task, makes the commit ledger easier to understand, plus it looks cool.

  • 🎨 :art: - Improve structure / format of the code.
  • ⚡️ :zap: - Improve performance.
  • 🔥 :fire: - Remove code or files.
  • 🐛 :bug: - Fix a bug.
  • 🚑️ :ambulance: - Critical hotfix
  • :sparkles: - Introduce new features.
  • 📝 :memo: - Add or update documentation.
  • 🚀 :rocket: - Deploy stuff.
  • 💄 :lipstick: - Add or update the UI and style files.
  • 🎉 :tada: - Begin a project.
  • :white_check_mark: - Add, update, or pass tests.
  • 🔒️ :lock: - Fix security issues.
  • 🔖 :bookmark: - Make a Release or Version tag.
  • 🚨 :rotating_light: - Fix compiler / linter warnings.
  • 🚧 :construction: - Work in progress.
  • ⬆️ :arrow_up: - Upgrade dependencies.
  • 👷 :construction_worker: - Add or update CI build system.
  • ♻️ :recycle: - Refactor code.
  • 🩹 :adhesive_bandage: - Simple fix for a non-critical issue.
  • 🔧 :wrench: - Add or update configuration files.
  • 🍱 :bento: - Add or update assets.
  • 🗃️ :card_file_box: - Perform database schema related changes.
  • ✏️ :pencil2: - Fix typos.
  • 🌐 :globe_with_meridians: - Internationalization and translations.

For a full list of options, see gitmoji.dev

PR Guidelines#

Once you've made your changes, and pushed them to your fork or branch, you're ready to open a pull request!

For a pull request to be merged, it must:

  • Must be backwards compatible
  • The build, lint and tests (run by GH actions) must pass
  • There must not be any merge conflicts

When you submit your PR, include the required info, by filling out the PR template. Including:

  • A brief description of your changes
  • The issue, ticket or discussion number (if applicable)
  • For UI relate updates include a screenshot
  • If any dependencies were added, explain why it was needed, state the cost associated, and confirm it does not introduce any security issues
  • Finally, check the checkboxes, to confirm that the standards are met, and hit submit!

Resources for Beginners#

New to Web Development? Glad you're here! Dashy is a pretty simple app, so it should make a good candidate for your first PR. Presuming that you already have a basic knowledge of JavaScript, the following articles should point you in the right direction for getting up to speed with the technologies used in this project:

As well as Node, Git and Docker- you'll also need an IDE (e.g. VS Code or Vim) and a terminal (Windows users may find WSL more convenient).


App Info#

Style Guide#

Linting is done using ESLint, and using the Vue.js Styleguide, which is very similar to the AirBnB Styleguide. You can run yarn lint to report and fix issues. While the dev server is running, issues will be reported to the console automatically, and any lint errors will trigger the build to fail. Note that all lint checks must pass before any PR can be merged. Linting is also run as a git pre-commit hook

The most significant things to note are:

  • Indentation should be done with two spaces
  • Strings should use single quotes
  • All statements must end in a semi-colon
  • The final element in all objects must be preceded with a comma
  • Maximum line length is 100
  • There must be exactly one blank line between sections, before function names, and at the end of the file
  • With conditionals, put else on the same line as your if block's closing brace
  • All multiline blocks must use braces
  • Avoid console statements in the frontend

Styleguides:


Application Structure#

Files in the Root: ./#

├── package.json        # Project meta-data, dependencies and paths to scripts├── src/                # Project front-end source code├── server.js           # A Node.js server to serve up the /dist directory├── services/           # All server-side endpoints and utilities├── vue.config.js       # Vue.js configuration├── Dockerfile          # The blueprint for building the Docker container├── docker-compose.yml  # A Docker run command├── .env                # Location for any environmental variables├── yarn.lock           # Auto-generated list of current packages and version numbers├── docs/               # Markdown documentation├── README.md           # Readme, basic info for getting started├── LICENSE.md          # License for use

Frontend Source: ./src/#

./src├── App.vue                       # Vue.js starting file├── assets                        # Static non-compiled assets│  ├── fonts                      # .ttf font files│  ├── locales                    # All app text, each language in a separate JSON file│  ╰── interface-icons            # SVG icons used in the app├── components                    # All front-end Vue web components│  ├── Charts                     # Charting components for dynamically displaying widget data│  │  ├── Gauge.vue               # A speed-dial style chart for showing 0 - 100 values│  │  ╰── PercentageChart.vue     # A horizontal bar for showing percentage breakdowns│  ├── Configuration              # Components relating to the user config pop-up│  │  ├── AppInfoModal.vue        # A modal showing core app info, like version, language, etc│  │  ├── AppVersion.vue          # Shows current version from package.json, compares with GitHub│  │  ├── CloudBackupRestore.vue  # Form where the user manages cloud sync options│  │  ├── ConfigContainer.vue     # Main container, wrapping all other config components│  │  ├── CustomCss.vue           # Form where the user can input custom CSS│  │  ├── EditSiteMeta.vue        # Form where the user can edit site meta data│  │  ├── JsonEditor.vue          # JSON editor, where the user can modify the main config file│  │  ╰── RebuildApp.vue          # A component allowing user to trigger a rebuild through the UI│  ├── FormElements               # Basic form elements used throughout the app│  │  ├── Button.vue              # Standard button component│  │  ├── Radio.vue               # Standard radio button input│  │  ├── Select.vue              # Standard dropdown input selector│  │  ├── Input.vue               # Standard text field input component│  │  ╰── Toggle.vue              # Standard on / off toggle switch│  ├── InteractiveEditor          # Components for the interactive UI config editor│  │  ├── AddNewSectionLauncher   # Button that launches the EditSection form, used for adding new section│  │  ├── EditAppConfig.vue       # Form for editing appConfig│  │  ├── EditPageInfo.vue        # Form for editing pageInfo│  │  ├── EditSection.vue         # Form for adding / editing sections│  │  ├── EditItem.vue            # Form for adding or editing items│  │  ├── EditModeSaveMenu.vue    # The bar at the bottom of screen in edit mode, containing save buttons│  │  ├── EditModeTopBanner.vue   # The bar at the top of screen in edit mode│  │  ├── ExportConfigMenu.vue    # Modal for viewing / exporting edited config│  │  ├── MoveItemTo.vue          # Form for moving / copying items to other sections│  │  ╰── SaveCancelButtons.vue   # Buttons visible in all the edit menus, to save or cancel changes│  ├── LinkItems                  # Components for Sections and Link Items│  │  ├── Collapsable.vue         # The collapsible functionality of sections│  │  ├── IframeModal.vue         # Pop-up iframe modal, for viewing websites within the app│  │  ├── Item.vue                # Main link item, which is displayed within an item group│  │  ├── ItemGroup.vue           # Item group is a section containing icons│  │  ├── ItemIcon.vue            # The icon used by both items and sections│  │  ├── ItemOpenMethodIcon.vue  # A small icon, visible on hover, indicating opening method│  │  ├── ItemContextMenu.vue     # The right-click menu, for showing Item opening methods and info│  │  ├── SectionContextMenu.vue  # The right-click menu, for showing Section edit/ open options│  │  ╰── StatusIndicator.vue     # Traffic light dot, showing if app is online or down│  ├── Minimal View               # Components used for the startpage / minimal alternative view│  │  ├── MinimalHeading.vue      # Title part of minimal view│  │  ├── MinimalSearch.vue       # Search bar for minimal view│  │  ╰── MinimalSection.vue      # Tabbed-Item section for minimal view│  ├── PageStrcture               # Components relating the main structure of the page│  │  ├── Footer.vue              # Footer, visible at the bottom of all pages│  │  ├── Header.vue              # Header, visible at the top of pages, and includes title and nav│  │  ├── LoadingScreen.vue       # Splash screen shown on first load│  │  ├── Nav.vue                 # Navigation bar, includes a list of links│  │  ╰── PageTitle.vue           # Page title and sub-title, visible within the Header│  ├── Workspace                  # Components used for the multi-tasking/ Workspace view│  │  ├── MultiTaskingWeb.vue     # When multi-tasking enabled, generates new iframe│  │  ├── SideBar.vue             # The left sidebar for the workspace view│  │  ├── SideBarItem.vue         # App item for the sidebar view│  │  ├── SideBarSection.vue      # Collapsible collection of items within workspace sidebar│  │  ├── WebContent.vue          # Workspace iframe view, displays content of current app│  │  ╰── WidgetView.vue          # Workspace container for displaying widgets in main content│  ├── Widgets                    # Directory contains all custom widget components│  │  ╰── ....                    # Too many to list, see widget docs instead│  ╰── Settings                   # Components relating to the quick-settings, in the top-right│     ├── AuthButtons.vue         # Logout button and other app info│     ├── ConfigLauncher.vue      # Icon that when clicked will launch the Configuration component│     ├── CustomThemeMaker.vue    # Color pickers for letting user build their own theme│     ├── ItemSizeSelector.vue    # Set of buttons used to set and save item size│     ├── KeyboardShortcutInfo.vue# Small pop-up displaying the available keyboard shortcuts│     ├── LanguageSwitcher.vue    # Dropdown in a modal for changing app language│     ├── LayoutSelector.vue      # Set of buttons, letting the user select their desired layout│     ├── SearchBar.vue           # The input field in the header, used for searching the app│     ├── SettingsContainer.vue   # Container that wraps all the quick-settings components│     ╰── ThemeSelector.vue       # Drop-down menu enabling the user to select and change themes├── main.js                       # Main front-end entry point├── registerServiceWorker.js      # Registers and manages service workers, for PWA apps├── router.js                     # Defines all available application routes├── styles                        # Directory of all globally used common SCSS styles│  ├── color-palette.scss         # All color variable names and default values│  ├── color-themes.scss          # All variable values for built-in themes│  ├── dimensions.scss            # Dimensions and sizes as variables│  ├── global-styles.scss         # Basics and style resets used globally│  ├── media-queries.scss         # Screen sizes and media queries│  ├── style-helpers.scss         # SCSS functions used for modifying values│  ├── typography.scss            # Font and text styles used globally│  ╰── user-defined-themes.scss   # Empty, put any custom styles or themes here├── mixins                        # Reusable component bases, extended by other views / components│  ├── ChartingMixin.js           # Functions for rendering charts in widget components│  ├── GlancesMixin.js            # Functions for fetching system info from Glances for widgets│  ├── HomeMixin.js               # Functions for homepage, used by default, minimal and workspace views│  ╰── WidgetMixin.js             # Functions for all widgets, like data fetching, updating and error handling├── utils                         # Directory of re-used helper functions│  ├── ArrowKeyNavigation.js      # Functionality for arrow-key navigation│  ├── Auth.js                    # Handles all authentication related actions│  ├── CheckSectionVisibility.js  # Checks which parts of the page should be visible/ hidden based on config│  ├── ClickOutside.js            # A directive for detecting click, used to hide dropdown, modal or context menu│  ├── ConfigHelpers.js           # Helper functions for managing configuration│  ├── CloudBackup.js             # Functionality for encrypting, processing and network calls│  ├── ConfigSchema.json          # The schema, used to validate the users conf.yml file│  ├── ConfigAccumulator.js       # Central place for managing and combining config│  ├── ConfigHelpers.json         # Collection of helper functions to process config using accumulator│  ├── ConfigValidator.js         # A helper script that validates the config file against schema│  ├── CoolConsole.js             # Prints info, warning and error messages to browser console, with a cool style│  ├── defaults.js                # Global constants and their default values│  ├── emojis.json                # List of emojis with unicode and shortcode, used for emoji icon feature│  ├── EmojiUnicodeRegex.js       # Regular expression to validate emoji unicode format, for emoji icons│  ├── ErrorHandler.js            # Helper function called when an error is returned│  ├── InitServiceWorker.js       # Initializes and manages service worker, if enabled│  ├── Search.js                  # Helper functions for searching/ filtering items in all views│  ├── JsonToYaml.js              # Function that parses and converts raw JSON into valid YAML│  ├── KeycloakAuth.js            # Singleton class to manage Keycloak authentication│  ├── languages.js               # Handles fetching, switching and validating languages│  ╰── ThemeHelper.js             # Function that handles the fetching and setting of user themes╰── views                         # Directory of available pages, corresponding to available routes   ├── Home.vue                   # The home page container   ├── About.vue                  # About page   ├── Login.vue                  # TAuthentication page   ├── Minimal.vue                # The minimal view   ╰── Workspace.vue              # The workspace view with apps in sidebar

Visualisation of Source Directory#

File Breakdown


Development Tools#

Performance - Lighthouse#

The easiest method of checking performance is to use Chromium's build in auditing tool, Lighthouse. To run the test, open Developer Tools (usually F12) --> Lighthouse and click on the 'Generate Report' button at the bottom.

Dependencies - BundlePhobia#

BundlePhobia is a really useful app that lets you analyze the cost of adding any particular dependency to an application


Notes#

Known Warnings#

When running the build command, several warnings appear. These are not errors, and do not affect the security or performance of the application. They will be addressed in a future update

WARN A new version of sass-loader is available. Please upgrade for best experience. - Currently we're using an older version of SASS loader, since the more recent releases do not seem to be compatible with the Vue CLI's webpack configuration.

WARN asset size limit: The following asset(s) exceed the recommended size limit (244 KiB). - For the PWA to support Windows 10, a splash screen asset is required, and is quite large. This throws a warning, however PWA assets are not loaded until needed, so shouldn't have any impact on application performance. A similar warning is thrown for the Raleway font, and that is looking to be addressed.

- + \ No newline at end of file diff --git a/docs/development-guides/index.html b/docs/development-guides/index.html index 58e40efd..252f12d0 100644 --- a/docs/development-guides/index.html +++ b/docs/development-guides/index.html @@ -6,7 +6,7 @@ Development Guides | Dashy - + @@ -23,7 +23,7 @@ Then, from within the root of Dashy's directory, start the server, by runni export default { mixins: [WidgetMixin], data() { return { results: null, }; }, computed: { endpoint() { return `${widgetApiEndpoints.myApi}/something`; }, }, methods: { fetchData() { this.makeRequest(this.endpoint).then(this.processData); }, processData(data) { // Do processing any here, and set component data this.results = data; }, },};</script> <style scoped lang="scss"></style>

All widgets extend from the Widget mixin. This provides some basic functionality that is shared by all widgets. The mixin includes the following options, startLoading(), finishLoading(), error() and update().

  • Getting user options: options
    • Any user-specific config can be accessed with this.options.something (where something is the data key you're accessing)
  • Loading state: startLoading() and finishLoading()
    • You can show the loader with this.startLoading(), then when your data request completes, hide it again with this.finishLoading()
  • Error handling: error()
    • If something goes wrong (such as API error, or missing user parameters), then call this.error() to show message to user
  • Updating data: update()
    • When the user clicks the update button, or if continuous updates are enabled, then the update() method within your widget will be called

Step 2 - Adding Functionality#

Accessing User Options#

If your widget is going to accept any parameters from the user, then we can access these with this.options.[parmName]. It's best to put these as computed properties, which will enable us to check it exists, is valid, and if needed format it. For example, if we have an optional property called count (to determine number of results), we can do the following, and then reference it within our component with this.count

computed: {  count() {    if (!this.options.count) {      return 5;    }    return this.options.count;  },    ...},

Adding an API Endpoint#

If your widget makes a data request, then add the URL for the API endpoint to the widgetApiEndpoints array in defaults.js

widgetApiEndpoints: {  ...  exampleEndpoint: 'https://hub.dummyapis.com/ImagesList',},

Then in your widget file:

import { widgetApiEndpoints } from '@/utils/defaults';

For GET requests, you may need to add some parameters onto the end of the URL. We can use another computed property for this, for example:

endpoint() {  return `${widgetApiEndpoints.exampleEndpoint}?count=${this.count}`;},

Making an API Request#

Axios is used for making data requests, so import it into your component: import axios from 'axios';

Under the methods block, we'll create a function called fetchData, here we can use Axios to make a call to our endpoint.

fetchData() {  this.makeRequest(this.endpoint, this.headers).then(this.processData);},

There are three things happening here:

  • If the response completes successfully, we'll pass the results to another function that will handle them
  • If there's an error, then we call this.error(), which will show a message to the user
  • Whatever the result, once the request has completed, we call this.finishLoading(), which will hide the loader

Processing Response#

In the above example, we call the processData() method with the result from the API, so we need to create that under the methods section. How you handle this data will vary depending on what's returned by the API, and what you want to render to the user. But however you do it, you will likely need to create a data variable to store the response, so that it can be easily displayed in the HTML.

data() {  return {    myResults: null,  };},

And then, inside your processData() method, you can set the value of this, with:

`this.myResults = 'whatever'`

Rendering Response#

Now that the results are in the correct format, and stored as data variables, we can use them within the <template> to render results to the user. Again, how you do this will depend on the structure of your data, and what you want to display, but at it's simplest, it might look something like this:

<p class="results">{{ myResults }}</p>

Styling#

Styles can be written for your widget within the <style> block.

There are several color variables used by widgets, which extend from the base palette. Using these enables users to override colors to theme their dashboard, if they wish. The variables are: --widget-text-color, --widget-background-color and --widget-accent-color

<style scoped lang="scss">p.results {  color: var(--widget-text-color);}</style>

For examples of finished widget components, see the Widgets directory. Specifically, the XkcdComic.vue widget is quite minimal, so would make a good example, as will this example implementation.

Step 3 - Register#

Next, register your new widget in WidgetBase.vue. In this file, you'll need to add the following:

const COMPAT = {  ...  'example-widget': 'ExampleWidget',};

Here, the example-widget property name will be used to identify the widget when parsing the type property in a configuration file. The ExampleWidget string is used to dynamically import the widget, and therefore must match the widget's filename as it exists in the components/widgets folder.

Step 4 - Docs#

Finally, add some documentation for your widget in the Widget Docs, so that others know how to use it. Include the following information: Title, short description, screenshot, config options and some example YAML.

Summary: For a complete example of everything discussed here, see: 3da76ce


Respecting Config Permissions#

Any screen that displays part or all of the users config, must not be shown when the user has disabled viewing config.

This can be done by checking the allowViewConfig attribute of the permissions getter, in the store. First create a new computed property, like:

allowViewConfig() {  return this.$store.getters.permissions.allowViewConfig;},

Then wrap the part of your UI which displays config with: v-if="allowViewConfig"

If required, add a message showing that the component isn't available, using the AccessError component. E.g.

import AccessError from '@/components/Configuration/AccessError';
<AccessError v-else />

The $store.getters.permissions object also returns options for when and where config can be saved, using: allowWriteToDisk, and allowSaveLocally - both are booleans.

- + \ No newline at end of file diff --git a/docs/icons/index.html b/docs/icons/index.html index f1618540..58c189b4 100644 --- a/docs/icons/index.html +++ b/docs/icons/index.html @@ -6,13 +6,13 @@ Icons | Dashy - +

Icons

Both sections and items can have an icon, which is specified using the icon attribute. Using icons improves the aesthetics of your UI and makes the app more intuitive to use. Dashy supports multiple different icon providers, usage instructions for which are explained here.


Favicons#

Dashy can auto-fetch an icon for a given service, using it's favicon. Just set icon: favicon to use this feature.

Since different websites host their favicons at different paths, for the best results Dashy can use an API to resolve a websites icon.

The default favicon API is allesedv.com, but you can change this under appConfig.faviconApi. If you'd prefer not to use an API, just set this value to local. You can also use different APIs for individual items, by setting icon: favicon-[api], e.g. favicon-clearbit.

The following favicon APIs are supported:

  • allesedv - allesedv.com is a highly efficient IPv6-enabled service
  • iconhorse - Icon.Horse returns quality icons for any site, with caching for speed and fallbacks for sites without an icon
  • clearbit - Clearbit returns high-quality square logos from mainstream websites
  • faviconkit - faviconkit.com good quality icons and most sites supported (Note: down as of Nov '21)
  • besticon - BestIcon fetches websites icons from manifest
  • mcapi - MC-API fetches default website favicon, originally a Minecraft util
  • duckduckgo - Returns decent quality website icons, from DuckDuckGo search
  • google - Official Google favicon API service, good support for all sites, but poor quality
  • yandex - Lower quality icons, but useful in some regions where other services are blocked
  • local - Set to local to fetch the default icon at /favicon.ico instead of using an API

If for a given service none of the APIs work in your situation, and nor does local, then the best option is to find the path of the services logo or favicon, and set the icon to the URL of the raw image. For example, icon: https://monitoring.local/faviconx128.png- you can find this path using the browser dev tools.


Font Awesome#

You can use any Font Awesome Icon simply by specifying it's identifier. This is in the format of [category] [name] and can be found on the page for that icon on the Font Awesome site. For example: fas fa-rocket, fab fa-monero or fas fa-unicorn.

Font-Awesome has a wide variety of free icons, but you can also use their pro icons if you have a membership. To do so, you need to specify your license key under: appConfig.fontAwesomeKey. This is usually a 10-digit string, for example 13014ae648.


Simple Icons#

SimpleIcons.org is a collection of 2000+ high quality, free and open source brand and logo SVG icons. Usage of which is very similar to font-awesome icons. First find the glyph you want to use on the website, then just set your icon the the simple icon slug, prefixed with si-.

For example:

sections:- name: Simple Icons Example  items:  - title: Portainer    icon: si-portainer  - title: FreeNAS    icon: si-freenas  - title: NextCloud    icon: si-nextcloud  - title: Home Assistant    icon: si-homeassistant

Generative Icons#

To uses a unique and programmatically generated icon for a given service just set icon: generative. This is particularly useful when you have a lot of similar services with a different IP or port, and no specific icon. These icons are generated with DiceBear (or Evatar for fallback), and use a hash of the services domain/ ip for entropy, so each domain will have a unique icon.


Emoji Icons#

You can use almost any emoji as an icon for items or sections. You can specify the emoji either by pasting it directly, using it's unicode ( e.g. 'U+1F680') or shortcode (e.g. ':rocket:'). You can find these codes for any emoji using Emojipedia (near the bottom of emoji each page), or for a quick reference to emoji shortcodes, check out emojis.ninja by @nomanoff.

For example, these will all render the same rocket (🚀) emoji: icon: ':rocket:' or icon: 'U+1F680' or icon: 🚀


Home-Lab Icons#

The dashboard-icons repo by @WalkxCode provides a comprehensive collection of 360+ high-quality PNG icons for commonly self-hosted services. Dashy natively supports these icons, and you can use them just by specifying the icon name (without extension) preceded by hl-. See here for a full list of all available icons. Note that these are fetched and cached strait from GitHub, so if you require offline access, the Local Icons method may be a better option for you.

For example:

sections:- name: Home Lab Icons Example  items:  - title: AdGuard Home    icon: hl-adguardhome  - title: Long Horn    icon: hl-longhorn  - title: Nagios    icon: hl-nagios  - title: Whoogle Search    icon: hl-whooglesearch


Material Design Icons#

Dashy also supports 5000+ material-design-icons. To use these, first find the name/ slug for your icon here, and then prefix is with mdi-.

For example:

sections:- name: Material Design Icons Example  items:  - title: Alien Icon    icon: mdi-alien  - title: Fire Icon    icon: mdi-fire  - title: Dino Icon    icon: mdi-google-downasaur


Icons by URL#

You can also set an icon by passing in a valid URL pointing to the icons location. For example icon: https://i.ibb.co/710B3Yc/space-invader-x256.png, this can be in .png, .jpg or .svg format, and hosted anywhere (local or remote) - so long as it's accessible from where you are hosting Dashy. The icon will be automatically scaled to fit, however loading in a lot of large icons may have a negative impact on performance, especially if you visit Dashy from new devices often.


Local Icons#

You may also want to store your icons locally, bundled within Dashy so that there is no reliance on outside services. This can be done by putting the icons within Dashy's ./public/item-icons/ directory. If you are using Docker, then the easiest option is to map a volume from your host system, for example: -v /local/image/directory:/app/public/item-icons/. To reference an icon stored locally, just specify it's name and extension. For example, if my icon was stored in /app/public/item-icons/maltrail.png, then I would just set icon: maltrail.png.

You can also use sub-folders within the item-icons directory to keep things organized. You would then specify an icon with it's folder name slash image name. For example: networking/monit.png


Default Icon#

If you'd like to set a default icon, to be applied to any items which don't have an icon already set, then this can be done under appConfig.defaultIcon.


No Icon#

If you don't wish for a given item or section to have an icon, just leave out the icon attribute.


Icon Collections and Resources#

The following websites provide good-quality, free icon sets. To use any of these icons, either copy the link to the raw icon (it should end in .svg or .png) and paste it as your icon, or download and save the icons in /public/item-icons / mapped Docker volume. Full credit to the authors, please see the licenses for each service for usage and copyright information.

If you are a student, then you can get free access to premium icons on Icon Scout or Icons8 using the GitHub Student Pack.


Notes#

If you are using icons from an external source, these will be fetched on initial page load automatically, if and when needed. But combining icons from multiple services may have a negative impact on performance.

You can improve load speeds, by downloading your required icons, and serving them locally. Scaling icons to the minimum required dimensions (e.g. 128x128 or 64x64) will also greatly improve application load times.

For icons from external sources, please see the Privacy Policies and Licenses for that provider.

- + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 5158557e..607262cf 100644 --- a/docs/index.html +++ b/docs/index.html @@ -6,13 +6,13 @@ Dashy | Dashy - +
- + \ No newline at end of file diff --git a/docs/license/index.html b/docs/license/index.html index 6a4bf5bd..9e68c47e 100644 --- a/docs/license/index.html +++ b/docs/license/index.html @@ -6,7 +6,7 @@ license | Dashy - + @@ -16,7 +16,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.
- + \ No newline at end of file diff --git a/docs/management/index.html b/docs/management/index.html index ece0da1f..f1ec6ec7 100644 --- a/docs/management/index.html +++ b/docs/management/index.html @@ -6,32 +6,32 @@ App Management | Dashy - +
-

App Management

The following article is a primer on managing self-hosted apps. It covers everything from keeping the Dashy (or any other app) up-to-date, secure, backed up, to other topics like auto-starting, monitoring, log management, web server configuration and using custom domains.

Contents#


Providing Assets#

Although not essential, you will most likely want to provide several assets to your running app.

This is easy to do using Docker Volumes, which lets you share a file or directory between your host system, and the container. Volumes are specified in the Docker run command, or Docker compose file, using the --volume or -v flags. The value of which consists of the path to the file / directory on your host system, followed by the destination path within the container. Fields are separated by a colon (:), and must be in the correct order. For example: -v ~/alicia/my-local-conf.yml:/app/public/conf.yml

In Dashy, commonly configured resources include:

  • ./public/conf.yml - Your main application config file
  • ./public/item-icons - A directory containing your own icons. This allows for offline access, and better performance than fetching from a CDN
  • Also within ./public you'll find standard website assets, including favicon.ico, manifest.json, robots.txt, etc. There's no need to pass these in, but you can do so if you wish
  • /src/styles/user-defined-themes.scss - A stylesheet for applying custom CSS to your app. You can also write your own themes here.

⬆️ Back to Top


Running Commands#

If you're running an app in Docker, then commands will need to be passed to the container to be executed. This can be done by preceding each command with docker exec -it [container-id], where container ID can be found by running docker ps. For example docker exec -it 26c156c467b4 yarn build. You can also enter the container, with docker exec -it [container-id] /bin/ash, and navigate around it with normal Linux commands.

Dashy has several commands that can be used for various tasks, you can find a list of these either in the Developing Docs, or by looking at the package.json. These can be used by running yarn [command-name].

⬆️ Back to Top


Healthchecks#

Healthchecks are configured to periodically check that Dashy is up and running correctly on the specified port. By default, the health script is called every 5 minutes, but this can be modified with the --health-interval option. You can check the current container health with: docker inspect --format "{{json .State.Health }}" [container-id], and a summary of health status will show up under docker ps. You can also manually request the current application status by running docker exec -it [container-id] yarn health-check. You can disable healthchecks altogether by adding the --no-healthcheck flag to your Docker run command.

To restart unhealthy containers automatically, check out Autoheal. This image watches for unhealthy containers, and automatically triggers a restart. (This is a stand in for Docker's --exit-on-unhealthy that was proposed, but not merged). There's also Deunhealth, which is super light-weight, and doesn't require network access.

docker run -d \    --name autoheal \    --restart=always \    -e AUTOHEAL_CONTAINER_LABEL=all \    -v /var/run/docker.sock:/var/run/docker.sock \    willfarrell/autoheal

⬆️ Back to Top


Logs and Performance#

Container Logs#

You can view logs for a given Docker container with docker logs [container-id], add the --follow flag to stream the logs. For more info, see the Logging Documentation. There's also Dozzle, a useful tool, that provides a web interface where you can stream and query logs from all your running containers from a single web app.

Container Performance#

You can check the resource usage for your running Docker containers with docker stats or docker stats [container-id]. For more info, see the Stats Documentation. There's also cAdvisor, a useful web app for viewing and analyzing resource usage and performance of all your running containers.

Management Apps#

You can also view logs, resource usage and other info as well as manage your entire Docker workflow in third-party Docker management apps. For example Portainer an all-in-one open source management web UI for Docker and Kubernetes, or LazyDocker a terminal UI for Docker container management and monitoring.

Advanced Logging and Monitoring#

Docker supports using Prometheus to collect logs, which can then be visualized using a platform like Grafana. For more info, see this guide. If you need to route your logs to a remote syslog, then consider using logspout. For enterprise-grade instances, there are managed services, that make monitoring container logs and metrics very easy, such as Sematext with Logagent.

⬆️ Back to Top


Auto-Starting at System Boot#

You can use Docker's restart policies to instruct the container to start after a system reboot, or restart after a crash. Just add the --restart=always flag to your Docker compose script or Docker run command. For more information, see the docs on Starting Containers Automatically.

For Podman, you can use systemd to create a service that launches your container, the docs explains things further. A similar approach can be used with Docker, if you need to start containers after a reboot, but before any user interaction.

To restart the container after something within it has crashed, consider using docker-autoheal by @willfarrell, a service that monitors and restarts unhealthy containers. For more info, see the Healthchecks section above.

⬆️ Back to Top


Updating#

Dashy is under active development, so to take advantage of the latest features, you may need to update your instance every now and again.

Updating Docker Container#

  1. Pull latest image: docker pull lissy93/dashy:latest
  2. Kill off existing container
    • Find container ID: docker ps
    • Stop container: docker stop [container_id]
    • Remove container: docker rm [container_id]
  3. Spin up new container: docker run [params] lissy93/dashy

Automatic Docker Updates#

You can automate the above process using Watchtower. -Watchtower will watch for new versions of a given image on Docker Hub, pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially.

To get started, spin up the watchtower container:

docker run -d \  --name watchtower \  -v /var/run/docker.sock:/var/run/docker.sock \  containrrr/watchtower

For more information, see the Watchtower Docs

Updating Dashy from Source#

Stop your current instance of Dashy, then navigate into the source directory. Pull down the latest code, with git pull origin master, then update dependencies with yarn, rebuild with yarn build, and start the server again with yarn start.

⬆️ Back to Top


Backing Up#

Backing Up Containers#

You can make a backup of any running container really easily, using docker commit and save it with docker export, to do so:

  • First find the container ID, you can do this with docker container ls
  • Now to create the snapshot, just run docker commit -p [container-id] my-backup
  • Finally, to save the backup locally, run docker save -o ~/dashy-backup.tar my-backup
  • If you want to push this to a container registry, run docker push my-backup:latest

Note that this will not include any data in docker volumes, and the process here is a bit different. Since these files exist on your host system, if you have an existing backup solution implemented, you can incorporate and volume files within that system.

Backing Up Volumes#

offen/docker-volume-backup is a useful tool for periodic Docker volume backups, to any S3-compatible storage provider. It's run as a light-weight Docker container, and is easy to setup, and also supports GPG-encryption, email notification, and routing away older backups.

To get started, create a docker-compose similar to the example below, and then start the container. For more info, check out their documentation, which is very clear.

version: '3'services:  backup:    image: offen/docker-volume-backup:latest    environment:      BACKUP_CRON_EXPRESSION: "0 * * * *"      BACKUP_PRUNING_PREFIX: backup-      BACKUP_RETENTION_DAYS: 7      AWS_BUCKET_NAME: backup-bucket      AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE      AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY    volumes:      - data:/backup/my-app-backup:ro      - /var/run/docker.sock:/var/run/docker.sock:rovolumes:  data:

It's worth noting that this process can also be done manually, using the following commands:

Backup:

docker run --rm -v some_volume:/volume -v /tmp:/backup alpine tar -cjf /backup/some_archive.tar.bz2 -C /volume ./

Restore:

docker run --rm -v some_volume:/volume -v /tmp:/backup alpine sh -c "rm -rf /volume/* /volume/..?* /volume/.[!.]* ; tar -C /volume/ -xjf /backup/some_archive.tar.bz2"

Dashy-Specific Backup#

Since Dashy is open source, and freely available, providing you're configuration data is passed in as volumes, there shouldn't be any need to backup the main container. Your main config file, and any assets you're using should be kept backed up, preferably in at least two places, and you should ensure that you can easily restore from backup, if needed.

Dashy also has a built-in cloud backup feature, which is free for personal users, and will let you make and restore fully encrypted backups of your config directly through the UI. To learn more, see the Cloud Backup Docs

⬆️ Back to Top


Scheduling#

If you need to periodically schedule the running of a given command on Dashy (or any other container), then a useful tool for doing so it ofelia. This runs as a Docker container and is really useful for things like backups, logging, updating, notifications, etc. Crons are specified using Go's crontab format, and a useful tool for visualizing this is crontab.guru. This can also be done natively with Alpine: docker run -it alpine ls /etc/periodic. -I recommend combining this with healthchecks for easy monitoring of jobs, and failure notifications.

⬆️ Back to Top


SSL Certificates#

Enabling HTTPS with an SSL certificate is recommended, especially if you are hosting Dashy anywhere other than your home. This will ensure that all traffic is encrypted in transit.

Auto-SSL#

If you are using NGINX Proxy Manager, then SSL is supported out of the box. Once you've added your proxy host and web address, then set the scheme to HTTPS, then under the SSL Tab select "Request a new SSL certificate" and follow the on-screen instructions.

If you're hosting Dashy behind Cloudflare, then they offer free and easy SSL- all you need to do is enable it under the SSL/TLS tab. Or if you are using shared hosting, you may find this tutorial helpful.

Getting a Self-Signed SSL Certificate#

Let's Encrypt is a global Certificate Authority, providing free SSL/TLS Domain Validation certificates in order to enable secure HTTPS access to your website. They have good browser/ OS compatibility with their ISRG X1 and DST CA X3 root certificates, support Wildcard issuance done via ACMEv2 using the DNS-01 and have Multi-Perspective Validation. Let's Encrypt provide CertBot an easy app for generating and setting up an SSL certificate.

This process can be automated, using something like the Docker-NGINX-Auto-SSL Container to generate and renew certificates when needed.

If you're not so comfortable on the command line, then you can use a tool like SSL For Free or ZeroSSL to generate your cert. They also provide step-by-step setup instructions for most platforms.

Passing a Self-Signed Certificate to Dashy#

Once you've generated your SSL cert, you'll need to pass it to Dashy. This can be done by specifying the paths to your public and private keys using the SSL_PRIV_KEY_PATH and SSL_PUB_KEY_PATH environmental variables. Or if you're using Docker, then just pass public + private SSL keys in under /etc/ssl/certs/dashy-pub.pem and /etc/ssl/certs/dashy-priv.key respectively, e.g:

docker run -d \  -p 8080:80 \  -v ~/my-private-key.key:/etc/ssl/certs/dashy-priv.key:ro \  -v ~/my-public-key.pem:/etc/ssl/certs/dashy-pub.pem:ro \  lissy93/dashy:latest

By default the SSL port is 443 within a Docker container, or 4001 if running on bare metal, but you can override this with the SSL_PORT environmental variable.

Once everything is setup, you can verify your site is secured using a tool like SSL Checker.

⬆️ Back to Top


Authentication#

Dashy natively supports secure authentication using KeyCloak. There is also a Simple Auth feature that doesn't require any additional setup. Usage instructions for both, as well as alternative auth methods, has now moved to the Authentication Docs page.

⬆️ Back to Top


Managing Containers with Docker Compose#

When you have a lot of containers, it quickly becomes hard to manage with docker run commands. The solution to this is docker compose, a handy tool for defining all a containers run settings in a single YAML file, and then spinning up that container with a single short command - docker compose up. A good example of which can be seen in @abhilesh's docker compose collection.

You can use Dashy's default docker-compose.yml file as a template, and modify it according to your needs.

An example Docker compose, using the default base image from DockerHub, might look something like this:

---version: "3.8"services:  dashy:    container_name: Dashy    image: lissy93/dashy    volumes:      - /root/my-config.yml:/app/public/conf.yml    ports:      - 4000:80    environment:      - BASE_URL=/my-dashboard    restart: unless-stopped    healthcheck:      test: ['CMD', 'node', '/app/services/healthcheck']      interval: 1m30s      timeout: 10s      retries: 3      start_period: 40s

⬆️ Back to Top


Passing in Environmental Variables#

With Docker, you can define environmental variables under the environment section of your Docker compose file. Environmental variables are used to configure high-level settings, usually before the config file has been read. For a list of all supported env vars in Dashy, see the developing docs, or the default .env file.

A common use case, is to run Dashy under a sub-page, instead of at the root of a URL (e.g. https://my-homelab.local/dashy instead of https://dashy.my-homelab.local). In this use-case, you'd specify the BASE_URL variable in your compose file.

environment:  - BASE_URL=/dashy

You can also do the same thing with the docker run command, using the --env flag. -If you've got many environmental variables, you might find it useful to put them in a .env file. Similarly, for Docker run you can use --env-file if you'd like to pass in a file containing all your environmental variables.

⬆️ Back to Top


Setting Headers#

Any external requests made to a different origin (app/ service under a different domain) will be blocked if the correct headers are not specified. This is known as Cross-Origin Resource Sharing (CORS) and is a security feature built into modern browsers.

If you see a CORS error in your console, this can be easily fixed by setting the correct headers. This is not a bug with Dashy, so please don't raise it as a bug!

Example Headers#

The following section briefly outlines how you can set headers for common web proxies/ servers. More info can be found in the documentation for the proxy that you are using, or in the MDN Docs.

These examples are using:

  • Access-Control-Allow-Origin header, but depending on what type of content you are enabling, this will vary. For example, to allow a site to be loaded in an iframe (for the modal or workspace views) you would use X-Frame-Options.
  • The domain root (/), if your're hosting from a sub-page, replace that with your path.
  • A wildcard (*), which would allow access from traffic on any domain, this is discouraged, and you should replace it with the URL where you are hosting Dashy. Note that for requests that transport sensitive info, like credentials (e.g. Keycloak login), the wildcard is disallowed all together and will be blocked.

Caddy#

See Caddy header docs for more info.

headers / {  Access-Control-Allow-Origin *}

NGINX#

See NGINX ngx_http_headers_module docs for more info.

location / {  add_header Access-Control-Allow-Origin *;}

Note this can also be done through the UI, using NGINX Proxy Manager.

Traefik#

See Træfɪk CORS headers docs for more info.

labels:  - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"  - "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org"  - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"  - "traefik.http.middlewares.testheader.headers.addvaryheader=true"

HAProxy#

See HAProxy Rewrite Response Docs for more info.

/   http-response add-header Access-Control-Allow-Origin *

Apache#

See Apache mode_headers docs for more info.

Header always set Access-Control-Allow-Origin "*"

Squid#

See Squid request_header_access docs for more info.

request_header_access Authorization allow all

⬆️ Back to Top


Remote Access#

WireGuard#

Using a VPN is one of the easiest ways to provide secure, full access to your local network from remote locations. WireGuard is a reasonably new open source VPN protocol, that was designed with ease of use, performance and security in mind. Unlike OpenVPN, it doesn't need to recreate the tunnel whenever connection is dropped, and it's also much easier to setup, using shared keys instead.

  • Install Wireguard - See the Install Docs for download links + instructions
    • On Debian-based systems, it's sudo apt install wireguard
  • Generate a Private Key - Run wg genkey on the Wireguard server, and copy it to somewhere safe for later
  • Create Server Config - Open or create a file at /etc/wireguard/wg0.conf and under [Interface] add the following (see example below):
    • Address - as a subnet of all desired IPs
    • PrivateKey - that you just generated
    • ListenPort - Default is 51820, but can be anything
  • Get Client App - Download the WG client app for your platform (Linux, Windows, MacOS, Android or iOS are all supported)
  • Create new Client Tunnel - On your client app, there should be an option to create a new tunnel, when doing so a client private key will be generated (but if not, use the wg genkey command again), and keep it somewhere safe. A public key will also be generated, and this will go in our saver config
  • Add Clients to Server Config - Head back to your wg0.conf file on the server, create a [Peer] section, and populate the following info
    • AllowedIPs - List of IP address inside the subnet, the client should have access to
    • PublicKey - The public key for the client you just generated
  • Start the Server - You can now start the WG server, using: wg-quick up wg0 on your server
  • Finish Client Setup - Head back to your client device, and edit the config file, leave the private key as is, and add the following fields:
    • PublicKey - The public key of the server
    • Address - This should match the AllowedIPs section on the servers config file
    • DNS - The DNS server that'll be used when accessing the network through the VPN
    • Endpoint - The hostname or IP + Port where your WG server is running (you may need to forward this in your firewall's settings)
  • Done - Your clients should now be able to connect to your WG server :) Depending on your networks firewall rules, you may need to port forward the address of your WG server

Example Server Config#

# Server file[Interface]# Which networks does my interface belong to? Notice: /24 and /64Address = 10.5.0.1/24, 2001:470:xxxx:xxxx::1/64PrivateKey = xxxListenPort = 51820
+

App Management

The following article is a primer on managing self-hosted apps. It covers everything from keeping the Dashy (or any other app) up-to-date, secure, backed up, to other topics like auto-starting, monitoring, log management, web server configuration and using custom domains.

Contents#


Providing Assets#

Although not essential, you will most likely want to provide several assets to your running app.

This is easy to do using Docker Volumes, which lets you share a file or directory between your host system, and the container. Volumes are specified in the Docker run command, or Docker compose file, using the --volume or -v flags. The value of which consists of the path to the file / directory on your host system, followed by the destination path within the container. Fields are separated by a colon (:), and must be in the correct order. For example: -v ~/alicia/my-local-conf.yml:/app/public/conf.yml

In Dashy, commonly configured resources include:

  • ./public/conf.yml - Your main application config file
  • ./public/item-icons - A directory containing your own icons. This allows for offline access, and better performance than fetching from a CDN
  • Also within ./public you'll find standard website assets, including favicon.ico, manifest.json, robots.txt, etc. There's no need to pass these in, but you can do so if you wish
  • /src/styles/user-defined-themes.scss - A stylesheet for applying custom CSS to your app. You can also write your own themes here.

⬆️ Back to Top


Running Commands#

If you're running an app in Docker, then commands will need to be passed to the container to be executed. This can be done by preceding each command with docker exec -it [container-id], where container ID can be found by running docker ps. For example docker exec -it 26c156c467b4 yarn build. You can also enter the container, with docker exec -it [container-id] /bin/ash, and navigate around it with normal Linux commands.

Dashy has several commands that can be used for various tasks, you can find a list of these either in the Developing Docs, or by looking at the package.json. These can be used by running yarn [command-name].

⬆️ Back to Top


Healthchecks#

Healthchecks are configured to periodically check that Dashy is up and running correctly on the specified port. By default, the health script is called every 5 minutes, but this can be modified with the --health-interval option. You can check the current container health with: docker inspect --format "{{json .State.Health }}" [container-id], and a summary of health status will show up under docker ps. You can also manually request the current application status by running docker exec -it [container-id] yarn health-check. You can disable healthchecks altogether by adding the --no-healthcheck flag to your Docker run command.

To restart unhealthy containers automatically, check out Autoheal. This image watches for unhealthy containers, and automatically triggers a restart. (This is a stand in for Docker's --exit-on-unhealthy that was proposed, but not merged). There's also Deunhealth, which is super light-weight, and doesn't require network access.

docker run -d \    --name autoheal \    --restart=always \    -e AUTOHEAL_CONTAINER_LABEL=all \    -v /var/run/docker.sock:/var/run/docker.sock \    willfarrell/autoheal

⬆️ Back to Top


Logs and Performance#

Container Logs#

You can view logs for a given Docker container with docker logs [container-id], add the --follow flag to stream the logs. For more info, see the Logging Documentation. There's also Dozzle, a useful tool, that provides a web interface where you can stream and query logs from all your running containers from a single web app.

Container Performance#

You can check the resource usage for your running Docker containers with docker stats or docker stats [container-id]. For more info, see the Stats Documentation. There's also cAdvisor, a useful web app for viewing and analyzing resource usage and performance of all your running containers.

Management Apps#

You can also view logs, resource usage and other info as well as manage your entire Docker workflow in third-party Docker management apps. For example Portainer an all-in-one open source management web UI for Docker and Kubernetes, or LazyDocker a terminal UI for Docker container management and monitoring.

Advanced Logging and Monitoring#

Docker supports using Prometheus to collect logs, which can then be visualized using a platform like Grafana. For more info, see this guide. If you need to route your logs to a remote syslog, then consider using logspout. For enterprise-grade instances, there are managed services, that make monitoring container logs and metrics very easy, such as Sematext with Logagent.

⬆️ Back to Top


Auto-Starting at System Boot#

You can use Docker's restart policies to instruct the container to start after a system reboot, or restart after a crash. Just add the --restart=always flag to your Docker compose script or Docker run command. For more information, see the docs on Starting Containers Automatically.

For Podman, you can use systemd to create a service that launches your container, the docs explains things further. A similar approach can be used with Docker, if you need to start containers after a reboot, but before any user interaction.

To restart the container after something within it has crashed, consider using docker-autoheal by @willfarrell, a service that monitors and restarts unhealthy containers. For more info, see the Healthchecks section above.

⬆️ Back to Top


Updating#

Dashy is under active development, so to take advantage of the latest features, you may need to update your instance every now and again.

Updating Docker Container#

  1. Pull latest image: docker pull lissy93/dashy:latest
  2. Kill off existing container
    • Find container ID: docker ps
    • Stop container: docker stop [container_id]
    • Remove container: docker rm [container_id]
  3. Spin up new container: docker run [params] lissy93/dashy

Automatic Docker Updates#

You can automate the above process using Watchtower. +Watchtower will watch for new versions of a given image on Docker Hub, pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially.

To get started, spin up the watchtower container:

docker run -d \  --name watchtower \  -v /var/run/docker.sock:/var/run/docker.sock \  containrrr/watchtower

For more information, see the Watchtower Docs

Updating Dashy from Source#

Stop your current instance of Dashy, then navigate into the source directory. Pull down the latest code, with git pull origin master, then update dependencies with yarn, rebuild with yarn build, and start the server again with yarn start.

⬆️ Back to Top


Backing Up#

Backing Up Containers#

You can make a backup of any running container really easily, using docker commit and save it with docker export, to do so:

  • First find the container ID, you can do this with docker container ls
  • Now to create the snapshot, just run docker commit -p [container-id] my-backup
  • Finally, to save the backup locally, run docker save -o ~/dashy-backup.tar my-backup
  • If you want to push this to a container registry, run docker push my-backup:latest

Note that this will not include any data in docker volumes, and the process here is a bit different. Since these files exist on your host system, if you have an existing backup solution implemented, you can incorporate and volume files within that system.

Backing Up Volumes#

offen/docker-volume-backup is a useful tool for periodic Docker volume backups, to any S3-compatible storage provider. It's run as a light-weight Docker container, and is easy to setup, and also supports GPG-encryption, email notification, and routing away older backups.

To get started, create a docker-compose similar to the example below, and then start the container. For more info, check out their documentation, which is very clear.

version: '3'services:  backup:    image: offen/docker-volume-backup:latest    environment:      BACKUP_CRON_EXPRESSION: "0 * * * *"      BACKUP_PRUNING_PREFIX: backup-      BACKUP_RETENTION_DAYS: 7      AWS_BUCKET_NAME: backup-bucket      AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE      AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY    volumes:      - data:/backup/my-app-backup:ro      - /var/run/docker.sock:/var/run/docker.sock:rovolumes:  data:

It's worth noting that this process can also be done manually, using the following commands:

Backup:

docker run --rm -v some_volume:/volume -v /tmp:/backup alpine tar -cjf /backup/some_archive.tar.bz2 -C /volume ./

Restore:

docker run --rm -v some_volume:/volume -v /tmp:/backup alpine sh -c "rm -rf /volume/* /volume/..?* /volume/.[!.]* ; tar -C /volume/ -xjf /backup/some_archive.tar.bz2"

Dashy-Specific Backup#

Since Dashy is open source, and freely available, providing you're configuration data is passed in as volumes, there shouldn't be any need to backup the main container. Your main config file, and any assets you're using should be kept backed up, preferably in at least two places, and you should ensure that you can easily restore from backup, if needed.

Dashy also has a built-in cloud backup feature, which is free for personal users, and will let you make and restore fully encrypted backups of your config directly through the UI. To learn more, see the Cloud Backup Docs

⬆️ Back to Top


Scheduling#

If you need to periodically schedule the running of a given command on Dashy (or any other container), then a useful tool for doing so it ofelia. This runs as a Docker container and is really useful for things like backups, logging, updating, notifications, etc. Crons are specified using Go's crontab format, and a useful tool for visualizing this is crontab.guru. This can also be done natively with Alpine: docker run -it alpine ls /etc/periodic. +I recommend combining this with healthchecks for easy monitoring of jobs, and failure notifications.

⬆️ Back to Top


SSL Certificates#

Enabling HTTPS with an SSL certificate is recommended, especially if you are hosting Dashy anywhere other than your home. This will ensure that all traffic is encrypted in transit.

Auto-SSL#

If you are using NGINX Proxy Manager, then SSL is supported out of the box. Once you've added your proxy host and web address, then set the scheme to HTTPS, then under the SSL Tab select "Request a new SSL certificate" and follow the on-screen instructions.

If you're hosting Dashy behind Cloudflare, then they offer free and easy SSL- all you need to do is enable it under the SSL/TLS tab. Or if you are using shared hosting, you may find this tutorial helpful.

Getting a Self-Signed SSL Certificate#

Let's Encrypt is a global Certificate Authority, providing free SSL/TLS Domain Validation certificates in order to enable secure HTTPS access to your website. They have good browser/ OS compatibility with their ISRG X1 and DST CA X3 root certificates, support Wildcard issuance done via ACMEv2 using the DNS-01 and have Multi-Perspective Validation. Let's Encrypt provide CertBot an easy app for generating and setting up an SSL certificate.

This process can be automated, using something like the Docker-NGINX-Auto-SSL Container to generate and renew certificates when needed.

If you're not so comfortable on the command line, then you can use a tool like SSL For Free or ZeroSSL to generate your cert. They also provide step-by-step setup instructions for most platforms.

Passing a Self-Signed Certificate to Dashy#

Once you've generated your SSL cert, you'll need to pass it to Dashy. This can be done by specifying the paths to your public and private keys using the SSL_PRIV_KEY_PATH and SSL_PUB_KEY_PATH environmental variables. Or if you're using Docker, then just pass public + private SSL keys in under /etc/ssl/certs/dashy-pub.pem and /etc/ssl/certs/dashy-priv.key respectively, e.g:

docker run -d \  -p 8080:80 \  -v ~/my-private-key.key:/etc/ssl/certs/dashy-priv.key:ro \  -v ~/my-public-key.pem:/etc/ssl/certs/dashy-pub.pem:ro \  lissy93/dashy:latest

By default the SSL port is 443 within a Docker container, or 4001 if running on bare metal, but you can override this with the SSL_PORT environmental variable.

Once everything is setup, you can verify your site is secured using a tool like SSL Checker.

⬆️ Back to Top


Authentication#

Dashy natively supports secure authentication using KeyCloak. There is also a Simple Auth feature that doesn't require any additional setup. Usage instructions for both, as well as alternative auth methods, has now moved to the Authentication Docs page.

⬆️ Back to Top


Managing Containers with Docker Compose#

When you have a lot of containers, it quickly becomes hard to manage with docker run commands. The solution to this is docker compose, a handy tool for defining all a containers run settings in a single YAML file, and then spinning up that container with a single short command - docker compose up. A good example of which can be seen in @abhilesh's docker compose collection.

You can use Dashy's default docker-compose.yml file as a template, and modify it according to your needs.

An example Docker compose, using the default base image from DockerHub, might look something like this:

---version: "3.8"services:  dashy:    container_name: Dashy    image: lissy93/dashy    volumes:      - /root/my-config.yml:/app/public/conf.yml    ports:      - 4000:80    environment:      - BASE_URL=/my-dashboard    restart: unless-stopped    healthcheck:      test: ['CMD', 'node', '/app/services/healthcheck']      interval: 1m30s      timeout: 10s      retries: 3      start_period: 40s

⬆️ Back to Top


Passing in Environmental Variables#

With Docker, you can define environmental variables under the environment section of your Docker compose file. Environmental variables are used to configure high-level settings, usually before the config file has been read. For a list of all supported env vars in Dashy, see the developing docs, or the default .env file.

A common use case, is to run Dashy under a sub-page, instead of at the root of a URL (e.g. https://my-homelab.local/dashy instead of https://dashy.my-homelab.local). In this use-case, you'd specify the BASE_URL variable in your compose file.

environment:  - BASE_URL=/dashy

You can also do the same thing with the docker run command, using the --env flag. +If you've got many environmental variables, you might find it useful to put them in a .env file. Similarly, for Docker run you can use --env-file if you'd like to pass in a file containing all your environmental variables.

⬆️ Back to Top


Setting Headers#

Any external requests made to a different origin (app/ service under a different domain) will be blocked if the correct headers are not specified. This is known as Cross-Origin Resource Sharing (CORS) and is a security feature built into modern browsers.

If you see a CORS error in your console, this can be easily fixed by setting the correct headers. This is not a bug with Dashy, so please don't raise it as a bug!

Example Headers#

The following section briefly outlines how you can set headers for common web proxies/ servers. More info can be found in the documentation for the proxy that you are using, or in the MDN Docs.

These examples are using:

  • Access-Control-Allow-Origin header, but depending on what type of content you are enabling, this will vary. For example, to allow a site to be loaded in an iframe (for the modal or workspace views) you would use X-Frame-Options.
  • The domain root (/), if your're hosting from a sub-page, replace that with your path.
  • A wildcard (*), which would allow access from traffic on any domain, this is discouraged, and you should replace it with the URL where you are hosting Dashy. Note that for requests that transport sensitive info, like credentials (e.g. Keycloak login), the wildcard is disallowed all together and will be blocked.

Caddy#

See Caddy header docs for more info.

headers / {  Access-Control-Allow-Origin *}

NGINX#

See NGINX ngx_http_headers_module docs for more info.

location / {  add_header Access-Control-Allow-Origin *;}

Note this can also be done through the UI, using NGINX Proxy Manager.

Traefik#

See Træfɪk CORS headers docs for more info.

labels:  - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"  - "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org"  - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"  - "traefik.http.middlewares.testheader.headers.addvaryheader=true"

HAProxy#

See HAProxy Rewrite Response Docs for more info.

/   http-response add-header Access-Control-Allow-Origin *

Apache#

See Apache mode_headers docs for more info.

Header always set Access-Control-Allow-Origin "*"

Squid#

See Squid request_header_access docs for more info.

request_header_access Authorization allow all

⬆️ Back to Top


Remote Access#

WireGuard#

Using a VPN is one of the easiest ways to provide secure, full access to your local network from remote locations. WireGuard is a reasonably new open source VPN protocol, that was designed with ease of use, performance and security in mind. Unlike OpenVPN, it doesn't need to recreate the tunnel whenever connection is dropped, and it's also much easier to setup, using shared keys instead.

  • Install Wireguard - See the Install Docs for download links + instructions
    • On Debian-based systems, it's sudo apt install wireguard
  • Generate a Private Key - Run wg genkey on the Wireguard server, and copy it to somewhere safe for later
  • Create Server Config - Open or create a file at /etc/wireguard/wg0.conf and under [Interface] add the following (see example below):
    • Address - as a subnet of all desired IPs
    • PrivateKey - that you just generated
    • ListenPort - Default is 51820, but can be anything
  • Get Client App - Download the WG client app for your platform (Linux, Windows, MacOS, Android or iOS are all supported)
  • Create new Client Tunnel - On your client app, there should be an option to create a new tunnel, when doing so a client private key will be generated (but if not, use the wg genkey command again), and keep it somewhere safe. A public key will also be generated, and this will go in our saver config
  • Add Clients to Server Config - Head back to your wg0.conf file on the server, create a [Peer] section, and populate the following info
    • AllowedIPs - List of IP address inside the subnet, the client should have access to
    • PublicKey - The public key for the client you just generated
  • Start the Server - You can now start the WG server, using: wg-quick up wg0 on your server
  • Finish Client Setup - Head back to your client device, and edit the config file, leave the private key as is, and add the following fields:
    • PublicKey - The public key of the server
    • Address - This should match the AllowedIPs section on the servers config file
    • DNS - The DNS server that'll be used when accessing the network through the VPN
    • Endpoint - The hostname or IP + Port where your WG server is running (you may need to forward this in your firewall's settings)
  • Done - Your clients should now be able to connect to your WG server :) Depending on your networks firewall rules, you may need to port forward the address of your WG server

Example Server Config#

# Server file[Interface]# Which networks does my interface belong to? Notice: /24 and /64Address = 10.5.0.1/24, 2001:470:xxxx:xxxx::1/64PrivateKey = xxxListenPort = 51820
 # Peer 1[Peer]PublicKey = xxx# Which source IPs can I expect from that peer? Notice: /32 and /128AllowedIps = 10.5.0.35/32, 2001:470:xxxx:xxxx::746f:786f/128
 # Peer 2[Peer]PublicKey = xxx# Which source IPs can I expect from that peer? This one has a LAN which can# access hosts/jails without NAT.# Peer 2 has a single IP address inside the VPN: it's 10.5.0.25/32AllowedIps = 10.5.0.25/32,10.21.10.0/24,10.21.20.0/24,10.21.30.0/24,10.31.0.0/24,2001:470:xxxx:xxxx::ca:571e/128

Example Client Config#

[Interface]# Which networks does my interface belong to? Notice: /24 and /64Address = 10.5.0.35/24, 2001:470:xxxx:xxxx::746f:786f/64PrivateKey = xxx
-# Server[Peer]PublicKey = xxx# I want to route everything through the server, both IPv4 and IPv6. All IPs are# thus available through the Server, and I can expect packets from any IP to# come from that peer.AllowedIPs = 0.0.0.0/0, ::0/0# Where is the server on the internet? This is a public address. The port# (:51820) is the same as ListenPort in the [Interface] of the Server file aboveEndpoint = 1.2.3.4:51820# Usually, clients are behind NAT. to keep the connection running, keep alive.PersistentKeepalive = 15

A useful tool for getting WG setup is Algo. It includes scripts and docs which cover almost all devices, platforms and clients, and has best practices implemented, and security features enabled. All of this is better explained in this blog post.

Reverse SSH Tunnel#

SSH (or Secure Shell) is a secure tunnel that allows you to connect to a remote host. Unlike the VPN methods, an SSH connection does not require an intermediary, and will not be affected by your IP changing. However it only allows you to access a single service at a time. SSH was really designed for terminal access, but because of the latter mentioned benefits it's useful to setup, as a fallback option.

Directly SSH'ing into your home, would require you to open a port (usually 22), which would be terrible for security, and is not recommended. However a reverse SSH connection is initiated from inside your network. Once the connection is established, the port is redirected, allowing you to use the established connection to SSH into your home network.

The issue you've probably spotted, is that most public, corporate, and institutional networks will block SSH connections. To overcome this, you'd have to establish a server outside of your homelab that your homelab's device could SSH into to establish the reverse SSH connection. You can then connect to that remote server (the mothership), which in turn connects to your home network.

Now all of this is starting to sound like quite a lot of work, but this is where services like remot3.it come in. They maintain the intermediary mothership server, and create the tunnel service for you. It's free for personal use, secure and easy. There are several similar services, such as RemoteIoT, or you could create your own on a cloud VPS (see this tutorial for more info on that).

Before getting started, you'll need to head over to Remote.it and create an account.

Then setup your local device:

  1. If you haven't already done so, you'll need to enable and configure SSH.
    • This is out-of-scope of this article, but I've explained it in detail in this post.
  2. Download the Remote.it install script from their GitHub
    • curl -LkO https://raw.githubusercontent.com/remoteit/installer/master/scripts/auto-install.sh
  3. Make it executable, with chmod +x ./auto-install.sh, and then run it with sudo ./auto-install.sh
  4. Finally, configure your device, by running sudo connectd_installer and following the on-screen instructions

And when you're ready to connect to it:

  1. Login to app.remote.it, and select the name of your device
  2. You should see a list of running services, click SSH
  3. You'll then be presented with some SSH credentials that you can now use to securely connect to your home, via the Remote.it servers

Done :)

TCP Tunnel#

If you're running Dashy on your local network, behind a firewall, but need to temporarily share it with someone external, this can be achieved quickly and securely using Ngrok. It's basically a super slick, encrypted TCP tunnel that provides an internet-accessible address that anyone use to access your local service, from anywhere.

To get started, Download and install Ngrok for your system, then just run ngrok http [port] (replace the port with the http port where Dashy is running, e.g. 8080). When using https, specify the full local url/ ip including the protocol.

Some Ngrok features require you to be authenticated, you can create a free account and generate a token in your dashboard, then run ngrok authtoken [token].

It's recommended to use authentication for any publicly accessible service. Dashy has an Auth feature built in, but an even easier method it to use the -auth switch. E.g. ngrok http -auth="username:password123" 8080

By default, your web app is assigned a randomly generated ngrok domain, but you can also use your own custom domain. Under the Domains Tab of your Ngrok dashboard, add your domain, and follow the CNAME instructions. You can now use your domain, with the -hostname switch, e.g. ngrok http -region=us -hostname=dashy.example.com 8080. If you don't have your own domain name, you can instead use a custom sub-domain (e.g. alicia-dashy.ngrok.io), using the -subdomain switch.

To integrate this into your docker-compose, take a look at the gtriggiano/ngrok-tunnel container.

There's so much more you can do with Ngrok, such as exposing a directory as a file browser, using websockets, relaying requests, rewriting headers, inspecting traffic, TLS and TCP tunnels and lots more. All or which is explained in the Documentation.

It's worth noting that Ngrok isn't the only option here, other options include: FRP, Inlets, Local Tunnel, TailScale, etc. Check out Awesome Tunneling for a list of alternatives.

⬆️ Back to Top


Custom Domain#

Using DNS#

For locally running services, a domain can be set up directly in the DNS records. This method is really quick and easy, and doesn't require you to purchase an actual domain. Just update your networks DNS resolver, to point your desired URL to the local IP where Dashy (or any other app) is running. For example, a line in your hosts file might look something like: 192.168.0.2 dashy.homelab.local.

If you're using Pi-Hole, a similar thing can be done in the /etc/dnsmasq.d/03-custom-dns.conf file, add a line like: address=/dashy.example.com/192.168.2.0 for each of your services.

If you're running OPNSense/ PfSense, then this can be done through the UI with Unbound, it's explained nicely in this article, by Dustin Casto.

Using NGINX#

If you're using NGINX, then you can use your own domain name, with a config similar to the below example.

upstream dashy {  server 127.0.0.1:32400;}
+# Server[Peer]PublicKey = xxx# I want to route everything through the server, both IPv4 and IPv6. All IPs are# thus available through the Server, and I can expect packets from any IP to# come from that peer.AllowedIPs = 0.0.0.0/0, ::0/0# Where is the server on the internet? This is a public address. The port# (:51820) is the same as ListenPort in the [Interface] of the Server file aboveEndpoint = 1.2.3.4:51820# Usually, clients are behind NAT. to keep the connection running, keep alive.PersistentKeepalive = 15

A useful tool for getting WG setup is Algo. It includes scripts and docs which cover almost all devices, platforms and clients, and has best practices implemented, and security features enabled. All of this is better explained in this blog post.

Reverse SSH Tunnel#

SSH (or Secure Shell) is a secure tunnel that allows you to connect to a remote host. Unlike the VPN methods, an SSH connection does not require an intermediary, and will not be affected by your IP changing. However it only allows you to access a single service at a time. SSH was really designed for terminal access, but because of the latter mentioned benefits it's useful to setup, as a fallback option.

Directly SSH'ing into your home, would require you to open a port (usually 22), which would be terrible for security, and is not recommended. However a reverse SSH connection is initiated from inside your network. Once the connection is established, the port is redirected, allowing you to use the established connection to SSH into your home network.

The issue you've probably spotted, is that most public, corporate, and institutional networks will block SSH connections. To overcome this, you'd have to establish a server outside of your homelab that your homelab's device could SSH into to establish the reverse SSH connection. You can then connect to that remote server (the mothership), which in turn connects to your home network.

Now all of this is starting to sound like quite a lot of work, but this is where services like remot3.it come in. They maintain the intermediary mothership server, and create the tunnel service for you. It's free for personal use, secure and easy. There are several similar services, such as RemoteIoT, or you could create your own on a cloud VPS (see this tutorial for more info on that).

Before getting started, you'll need to head over to Remote.it and create an account.

Then setup your local device:

  1. If you haven't already done so, you'll need to enable and configure SSH.
    • This is out-of-scope of this article, but I've explained it in detail in this post.
  2. Download the Remote.it install script from their GitHub
    • curl -LkO https://raw.githubusercontent.com/remoteit/installer/master/scripts/auto-install.sh
  3. Make it executable, with chmod +x ./auto-install.sh, and then run it with sudo ./auto-install.sh
  4. Finally, configure your device, by running sudo connectd_installer and following the on-screen instructions

And when you're ready to connect to it:

  1. Login to app.remote.it, and select the name of your device
  2. You should see a list of running services, click SSH
  3. You'll then be presented with some SSH credentials that you can now use to securely connect to your home, via the Remote.it servers

Done :)

TCP Tunnel#

If you're running Dashy on your local network, behind a firewall, but need to temporarily share it with someone external, this can be achieved quickly and securely using Ngrok. It's basically a super slick, encrypted TCP tunnel that provides an internet-accessible address that anyone use to access your local service, from anywhere.

To get started, Download and install Ngrok for your system, then just run ngrok http [port] (replace the port with the http port where Dashy is running, e.g. 8080). When using https, specify the full local url/ ip including the protocol.

Some Ngrok features require you to be authenticated, you can create a free account and generate a token in your dashboard, then run ngrok authtoken [token].

It's recommended to use authentication for any publicly accessible service. Dashy has an Auth feature built in, but an even easier method it to use the -auth switch. E.g. ngrok http -auth="username:password123" 8080

By default, your web app is assigned a randomly generated ngrok domain, but you can also use your own custom domain. Under the Domains Tab of your Ngrok dashboard, add your domain, and follow the CNAME instructions. You can now use your domain, with the -hostname switch, e.g. ngrok http -region=us -hostname=dashy.example.com 8080. If you don't have your own domain name, you can instead use a custom sub-domain (e.g. alicia-dashy.ngrok.io), using the -subdomain switch.

To integrate this into your docker-compose, take a look at the gtriggiano/ngrok-tunnel container.

There's so much more you can do with Ngrok, such as exposing a directory as a file browser, using websockets, relaying requests, rewriting headers, inspecting traffic, TLS and TCP tunnels and lots more. All or which is explained in the Documentation.

It's worth noting that Ngrok isn't the only option here, other options include: FRP, Inlets, Local Tunnel, TailScale, etc. Check out Awesome Tunneling for a list of alternatives.

⬆️ Back to Top


Custom Domain#

Using DNS#

For locally running services, a domain can be set up directly in the DNS records. This method is really quick and easy, and doesn't require you to purchase an actual domain. Just update your networks DNS resolver, to point your desired URL to the local IP where Dashy (or any other app) is running. For example, a line in your hosts file might look something like: 192.168.0.2 dashy.homelab.local.

If you're using Pi-Hole, a similar thing can be done in the /etc/dnsmasq.d/03-custom-dns.conf file, add a line like: address=/dashy.example.com/192.168.2.0 for each of your services.

If you're running OPNSense/ PfSense, then this can be done through the UI with Unbound, it's explained nicely in this article, by Dustin Casto.

Using NGINX#

If you're using NGINX, then you can use your own domain name, with a config similar to the below example.

upstream dashy {  server 127.0.0.1:32400;}
 server {  listen         80;  server_name    dashy.mydomain.com;
   # Setup SSL  ssl_certificate             /var/www/mydomain/sslcert.pem;  ssl_certificate_key         /var/www/mydomain/sslkey.pem;  ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;  ssl_ciphers                 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';  ssl_session_timeout         5m;  ssl_prefer_server_ciphers   on;
-  location / {    proxy_pass                http://dashy;    proxy_redirect            off;    proxy_buffering           off;    proxy_set_header          host              $host;    proxy_set_header          X-Real-IP         $remote_addr;    proxy_set_header          X-Forwarded-For   $proxy_add_x_forwarded_for;    proxy_next_upstream       error timeout     invalid_header http_500 http_502 http_503 http_504;  }}

Similarly, a basic Caddyfile might look like:

dashy.example.com {    reverse_proxy / nginx:80}

For more info, this guide on Setting up Domains with NGINX Proxy Manager and CloudFlare may be useful.

⬆️ Back to Top


Container Security#

Keep Docker Up-To-Date#

To prevent known container escape vulnerabilities, which typically end in escalating to root/administrator privileges, patching Docker Engine and Docker Machine is crucial. For more info, see the Docker Installation Docs.

Set Resource Quotas#

Docker enables you to limit resource consumption (CPU, memory, disk) on a per-container basis. This not only enhances system performance, but also prevents a compromised container from consuming a large amount of resources, in order to disrupt service or perform malicious activities. To learn more, see the Resource Constraints Docs

For example, to run Dashy with max of 1GB ram, and max of 50% of 1 CP core: + location / { proxy_pass http://dashy; proxy_redirect off; proxy_buffering off; proxy_set_header host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; }}

Similarly, a basic Caddyfile might look like:

dashy.example.com {    reverse_proxy / nginx:80}

For more info, this guide on Setting up Domains with NGINX Proxy Manager and CloudFlare may be useful.

⬆️ Back to Top


Container Security#

Keep Docker Up-To-Date#

To prevent known container escape vulnerabilities, which typically end in escalating to root/administrator privileges, patching Docker Engine and Docker Machine is crucial. For more info, see the Docker Installation Docs.

Set Resource Quotas#

Docker enables you to limit resource consumption (CPU, memory, disk) on a per-container basis. This not only enhances system performance, but also prevents a compromised container from consuming a large amount of resources, in order to disrupt service or perform malicious activities. To learn more, see the Resource Constraints Docs

For example, to run Dashy with max of 1GB ram, and max of 50% of 1 CP core: docker run -d -p 8080:80 --cpus=".5" --memory="1024m" lissy93/dashy:latest

Don't Run as Root#

Running a container with admin privileges gives it more power than it needs, and can be abused. Dashy does not need any root privileges, and Docker by default doesn't run containers as root, so providing you don't specifically type sudo, you should be all good here.

Note that if you're facing permission issues on Debian-based systems, you may need to add your user to the Docker group. First create the group: sudo groupadd docker, then add your (non-root) user: sudo usermod −aG docker [my-username], finally newgrp docker to refresh.

Specify a User#

One of the best ways to prevent privilege escalation attacks, is to configure the container to use an unprivileged user. This also means that any files created by the container and mounted, will be owned by the specified user (and not root), which makes things much easier.

You can specify a user, using the --user param, and should include the user ID (UID), which can be found by running id -u, and the and the group ID (GID), using id -g.

With Docker run, you specify it like: docker run --user 1000:1000 -p 8080:80 lissy93/dashy

Of if you're using Docker-compose, you could use an environmental variable

version: "3.8"services:  dashy:    image: lissy93/dashy    user: ${CURRENT_UID}    ports: [ 4000:80 ]

And then to set the variable, and start the container, run: CURRENT_UID=$(id -u):$(id -g) docker-compose up

Limit capabilities#

Docker containers run with a subset of Linux Kernal's Capabilities by default. It's good practice to drop privilege permissions that are not needed for any given container.

With Docker run, you can use the --cap-drop flag to remove capabilities, you can also use --cap-drop=all and then define just the required permissions using the --cap-add option. For a list of available capabilities, see the Privilege Capabilities Docs.

Note that dropping privileges and capabilities on runtime is not fool-proof, and often any leftover privileges can be used to re-escalate, see POS36-C.

Here's an example using docker-compose, removing privileges that are not required for Dashy to run:

version: "3.8"services:  dashy:    image: lissy93/dashy    ports: [ 4000:80 ]    cap_drop:    - ALL    cap_add:    - CHOWN    - SETGID    - SETUID    - DAC_OVERRIDE    - NET_BIND_SERVICE

Prevent new Privileges being Added#

To prevent processes inside the container from getting additional privileges, pass in the --security-opt=no-new-privileges:true option to the Docker run command (see docs).

Run Command: docker run --security-opt=no-new-privileges:true -p 8080:80 lissy93/dashy

Docker Compose

security_opt:- no-new-privileges:true

Disable Inter-Container Communication#

By default Docker containers can talk to each other (using docker0 bridged network). If you don't need this capability, then it should be disabled. This can be done with the --icc=false in your run command. You can learn more about how to facilitate secure communication between containers in the Compose Networking docs.

Don't Expose the Docker Daemon Socket#

Docker socket /var/run/docker.sock is the UNIX socket that Docker is listening to. This is the primary entry point for the Docker API. The owner of this socket is root. Giving someone access to it is equivalent to giving unrestricted root access to your host.

You should not enable TCP Docker daemon socket (-H tcp://0.0.0.0:XXX), as doing so exposes un-encrypted and unauthenticated direct access to the Docker daemon, and if the host is connected to the internet, the daemon on your computer can be used by anyone from the public internet- which is bad. If you need TCP, you should see the docs to understand how to do this more securely. -Similarly, never expose /var/run/docker.sock to other containers as a volume, as it can be exploited.

Use Read-Only Volumes#

You can specify that a specific volume should be read-only by appending :ro to the -v switch. For example, while running Dashy, if we want our config to be writable, but keep all other assets protected, we would do:

docker run -d \  -p 8080:80 \  -v ~/dashy-conf.yml:/app/public/conf.yml \  -v ~/dashy-icons:/app/public/item-icons:ro \  -v ~/dashy-theme.scss:/app/src/styles/user-defined-themes.scss:ro \  lissy93/dashy:latest

You can also prevent a container from writing any changes to volumes on your host's disk, using the --read-only flag. Although, for Dashy, you will not be able to write config changes to disk, when edited through the UI with this method. You could make this work, by specifying the config directory as a temp write location, with --tmpfs /app/public/conf.yml - but that this will not write the volume back to your host.

Set the Logging Level#

Logging is important, as it enables you to review events in the future, and in the case of a compromise this will let get an idea of what may have happened. The default log level is INFO, and this is also the recommendation, use --log-level info to ensure this is set.

Verify Image before Pulling#

Only use trusted images, from verified/ official sources. If an app is open source, it is more likely to be safe, as anyone can verify the code. There are also tools available for scanning containers,

Unless otherwise configured, containers can communicate among each other, so running one bad image may lead to other areas of your setup being compromised. Docker images typically contain both original code, as well as up-stream packages, and even if that image has come from a trusted source, the up-stream packages it includes may not have.

Specify the Tag#

Using fixed tags (as opposed to :latest ) will ensure immutability, meaning the base image will not change between builds. Note that for Dashy, the app is being actively developed, new features, bug fixes and general improvements are merged each week, and if you use a fixed version you will not enjoy these benefits. So it's up to you weather you would prefer a stable and reproducible environment, or the latest features and enhancements.

Container Security Scanning#

It's helpful to be aware of any potential security issues in any of the Docker images you are using. You can run a quick scan using Snyk on any image to output known vulnerabilities using Docker scan, e.g: docker scan lissy93/dashy:latest.

A similar product is Trivy, which is free an open source. First install it (with your package manager), then to scan an image, just run: trivy image lissy93/dashy:latest

For larger systems, RedHat Clair is an app for parsing image contents and reporting on any found vulnerabilities. You run it locally in a container, and configure it with YAML. It can be integrated with Red Hat Quay, to show results on a dashboard. Most of these use static analysis to find potential issues, and scan included packages for any known security vulnerabilities.

Registry Security#

Although over-kill for most users, you could run your own registry locally which would give you ultimate control over all images, see the Deploying a Registry Docs for more info. Another option is Docker Trusted Registry, it's great for enterprise applications, it sits behind your firewall, running on a swarm managed by Docker Universal Control Plane, and lets you securely store and manage your Docker images, mitigating the risk of breaches from the internet.

Security Modules#

Docker supports several modules that let you write your own security profiles.

AppArmoris a kernel module that proactively protects the operating system and applications from external or internal threats, by enabling you to restrict programs' capabilities with per-program profiles. You can specify either a security policy by name, or by file path with the apparmor flag in docker run. Learn more about writing profiles, here.

Seccomp (Secure Computing Mode) is a sandboxing facility in the Linux kernel that acts like a firewall for system calls (syscalls). It uses Berkeley Packet Filter (BPF) rules to filter syscalls and control how they are handled. These filters can significantly limit a containers access to the Docker Host's Linux kernel - especially for simple containers/applications. It requires a Linux-based Docker host, with secomp enabled, and you can check for this by running docker info | grep seccomp. A great resource for learning more about this is DockerLabs.

⬆️ Back to Top


Web Server Configuration#

The following section only applies if you are not using Docker, and would like to use your own web server

Dashy ships with a pre-configured Node.js server, in server.js which serves up the contents of the ./dist directory on a given port. You can start the server by running node server. Note that the app must have been build (run yarn build), and you need Node.js installed.

If you wish to run Dashy from a sub page (e.g. example.com/dashy), then just set the BASE_URL environmental variable to that page name (in this example, /dashy), before building the app, and the path to all assets will then resolve to the new path, instead of ./.

However, since Dashy is just a static web application, it can be served with whatever server you like. The following section outlines how you can configure a web server.

Note, that if you choose not to use server.js to serve up the app, you will loose access to the following features:

  • Loading page, while the app is building
  • Writing config file to disk from the UI
  • Website status indicators, and ping checks

Example Configs

NGINX#

Create a new file in /etc/nginx/sites-enabled/dashy

server {    listen 80;    listen [::]:80;
+Similarly, never expose /var/run/docker.sock to other containers as a volume, as it can be exploited.

Use Read-Only Volumes#

You can specify that a specific volume should be read-only by appending :ro to the -v switch. For example, while running Dashy, if we want our config to be writable, but keep all other assets protected, we would do:

docker run -d \  -p 8080:80 \  -v ~/dashy-conf.yml:/app/public/conf.yml \  -v ~/dashy-icons:/app/public/item-icons:ro \  -v ~/dashy-theme.scss:/app/src/styles/user-defined-themes.scss:ro \  lissy93/dashy:latest

You can also prevent a container from writing any changes to volumes on your host's disk, using the --read-only flag. Although, for Dashy, you will not be able to write config changes to disk, when edited through the UI with this method. You could make this work, by specifying the config directory as a temp write location, with --tmpfs /app/public/conf.yml - but that this will not write the volume back to your host.

Set the Logging Level#

Logging is important, as it enables you to review events in the future, and in the case of a compromise this will let get an idea of what may have happened. The default log level is INFO, and this is also the recommendation, use --log-level info to ensure this is set.

Verify Image before Pulling#

Only use trusted images, from verified/ official sources. If an app is open source, it is more likely to be safe, as anyone can verify the code. There are also tools available for scanning containers,

Unless otherwise configured, containers can communicate among each other, so running one bad image may lead to other areas of your setup being compromised. Docker images typically contain both original code, as well as up-stream packages, and even if that image has come from a trusted source, the up-stream packages it includes may not have.

Specify the Tag#

Using fixed tags (as opposed to :latest ) will ensure immutability, meaning the base image will not change between builds. Note that for Dashy, the app is being actively developed, new features, bug fixes and general improvements are merged each week, and if you use a fixed version you will not enjoy these benefits. So it's up to you weather you would prefer a stable and reproducible environment, or the latest features and enhancements.

Container Security Scanning#

It's helpful to be aware of any potential security issues in any of the Docker images you are using. You can run a quick scan using Snyk on any image to output known vulnerabilities using Docker scan, e.g: docker scan lissy93/dashy:latest.

A similar product is Trivy, which is free an open source. First install it (with your package manager), then to scan an image, just run: trivy image lissy93/dashy:latest

For larger systems, RedHat Clair is an app for parsing image contents and reporting on any found vulnerabilities. You run it locally in a container, and configure it with YAML. It can be integrated with Red Hat Quay, to show results on a dashboard. Most of these use static analysis to find potential issues, and scan included packages for any known security vulnerabilities.

Registry Security#

Although over-kill for most users, you could run your own registry locally which would give you ultimate control over all images, see the Deploying a Registry Docs for more info. Another option is Docker Trusted Registry, it's great for enterprise applications, it sits behind your firewall, running on a swarm managed by Docker Universal Control Plane, and lets you securely store and manage your Docker images, mitigating the risk of breaches from the internet.

Security Modules#

Docker supports several modules that let you write your own security profiles.

AppArmoris a kernel module that proactively protects the operating system and applications from external or internal threats, by enabling you to restrict programs' capabilities with per-program profiles. You can specify either a security policy by name, or by file path with the apparmor flag in docker run. Learn more about writing profiles, here.

Seccomp (Secure Computing Mode) is a sandboxing facility in the Linux kernel that acts like a firewall for system calls (syscalls). It uses Berkeley Packet Filter (BPF) rules to filter syscalls and control how they are handled. These filters can significantly limit a containers access to the Docker Host's Linux kernel - especially for simple containers/applications. It requires a Linux-based Docker host, with secomp enabled, and you can check for this by running docker info | grep seccomp. A great resource for learning more about this is DockerLabs.

⬆️ Back to Top


Web Server Configuration#

The following section only applies if you are not using Docker, and would like to use your own web server

Dashy ships with a pre-configured Node.js server, in server.js which serves up the contents of the ./dist directory on a given port. You can start the server by running node server. Note that the app must have been build (run yarn build), and you need Node.js installed.

If you wish to run Dashy from a sub page (e.g. example.com/dashy), then just set the BASE_URL environmental variable to that page name (in this example, /dashy), before building the app, and the path to all assets will then resolve to the new path, instead of ./.

However, since Dashy is just a static web application, it can be served with whatever server you like. The following section outlines how you can configure a web server.

Note, that if you choose not to use server.js to serve up the app, you will loose access to the following features:

  • Loading page, while the app is building
  • Writing config file to disk from the UI
  • Website status indicators, and ping checks

Example Configs

NGINX#

Create a new file in /etc/nginx/sites-enabled/dashy

server {    listen 80;    listen [::]:80;
     root /var/www/dashy/html;    index index.html;
     server_name your-domain.com www.your-domain.com;
     location / {        try_files $uri $uri/ =404;    }}

To use HTML5 history mode (appConfig.routingMode: history), replace the inside of the location block with: try_files $uri $uri/ /index.html;.

Then upload the build contents of Dashy's dist directory to that location. For example: scp -r ./dist/* [username]@[server_ip]:/var/www/dashy/html

Apache#

Copy Dashy's dist folder to your apache server, sudo cp -r ./dashy/dist /var/www/html/dashy.

In your Apache config, /etc/apche2/apache2.conf add:

<Directory /var/www/html>    Options Indexes FollowSymLinks    AllowOverride All    Require all granted</Directory>
-<IfModule mod_rewrite.c>  RewriteEngine On  RewriteBase /  RewriteRule ^index\.html$ - [L]  RewriteCond %{REQUEST_FILENAME} !-f  RewriteCond %{REQUEST_FILENAME} !-d  RewriteRule . /index.html [L]</IfModule>

Add a .htaccess file within /var/www/html/dashy/.htaccess, and add:

Options -MultiViewsRewriteEngine OnRewriteCond %{REQUEST_FILENAME} !-fRewriteRule ^ index.html [QSA,L]

Then restart Apache, with sudo systemctl restart apache2

Caddy#

Caddy v2

try_files {path} /

Caddy v1

rewrite {  regexp .*  to {path} /}

Firebase Hosting#

Create a file names firebase.json, and populate it with something similar to:

{  "hosting": {    "public": "dist",    "rewrites": [      {        "source": "**",        "destination": "/index.html"      }    ]  }}

cPanel#

  1. Login to your WHM
  2. Open 'Feature Manager' on the left sidebar
  3. Under 'Manage feature list', click 'Edit'
  4. Find 'Application manager' in the list, enable it and hit 'Save'
  5. Log into your users cPanel account, and under 'Software' find 'Application Manager'
  6. Click 'Register Application', fill in the form using the path that Dashy is located, and choose a domain, and hit 'Save'
  7. The application should now show up in the list, click 'Ensure dependencies', and move the toggle switch to 'Enabled'
  8. If you need to change the port, click 'Add environmental variable', give it the name 'PORT', choose a port number and press 'Save'.
  9. Dashy should now be running at your selected path an on a given port

⬆️ Back to Top


Running a Modified Version of the App#

If you'd like to make any code changes to the app, and deploy your modified version, this section briefly explains how.

The first step is to fork the project on GitHub, and clone it to your local system. Next, install the dependencies (yarn), and start the development server (yarn dev) and visit localhost:8080 in your browser. You can then make changes to the codebase, and see the live app update in real-time. Once you've finished, running yarn build will build the app for production, and output the assets into ./dist which can then be deployed using a web server, CDN or the built-in Node server with yarn start. For more info on all of this, take a look at the Developing Docs. To build your own Docker container from the modified app, see Building your Own Container

⬆️ Back to Top


Building your Own Container#

Similar to above, you'll first need to fork and clone Dashy to your local system, and then install dependencies.

Then, either use Dashy's default Dockerfile as is, or modify it according to your needs.

To build and deploy locally, first build the app with: docker build -t dashy ., and then start the app with docker run -p 8080:80 --name my-dashboard dashy. Or modify the docker-compose.yml file, replacing image: lissy93/dashy with build: . and run docker compose up.

Your container should now be running, and will appear in the list when you run docker container ls –a. If you'd like to enter the container, run docker exec -it [container-id] /bin/ash.

You may wish to upload your image to a container registry for easier access. Note that if you choose to do this on a public registry, please name your container something other than just 'dashy', to avoid confusion with the official image. -You can push your build image, by running: docker push ghcr.io/OWNER/IMAGE_NAME:latest. You will first need to authenticate, this can be done by running echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin, where CR_PAT is an environmental variable containing a token generated from your GitHub account. For more info, see the Container Registry Docs.

⬆️ Back to Top


- +<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L]</IfModule>

Add a .htaccess file within /var/www/html/dashy/.htaccess, and add:

Options -MultiViewsRewriteEngine OnRewriteCond %{REQUEST_FILENAME} !-fRewriteRule ^ index.html [QSA,L]

Then restart Apache, with sudo systemctl restart apache2

Caddy#

Caddy v2

try_files {path} /

Caddy v1

rewrite {  regexp .*  to {path} /}

Firebase Hosting#

Create a file names firebase.json, and populate it with something similar to:

{  "hosting": {    "public": "dist",    "rewrites": [      {        "source": "**",        "destination": "/index.html"      }    ]  }}

cPanel#

  1. Login to your WHM
  2. Open 'Feature Manager' on the left sidebar
  3. Under 'Manage feature list', click 'Edit'
  4. Find 'Application manager' in the list, enable it and hit 'Save'
  5. Log into your users cPanel account, and under 'Software' find 'Application Manager'
  6. Click 'Register Application', fill in the form using the path that Dashy is located, and choose a domain, and hit 'Save'
  7. The application should now show up in the list, click 'Ensure dependencies', and move the toggle switch to 'Enabled'
  8. If you need to change the port, click 'Add environmental variable', give it the name 'PORT', choose a port number and press 'Save'.
  9. Dashy should now be running at your selected path an on a given port

⬆️ Back to Top


Running a Modified Version of the App#

If you'd like to make any code changes to the app, and deploy your modified version, this section briefly explains how.

The first step is to fork the project on GitHub, and clone it to your local system. Next, install the dependencies (yarn), and start the development server (yarn dev) and visit localhost:8080 in your browser. You can then make changes to the codebase, and see the live app update in real-time. Once you've finished, running yarn build will build the app for production, and output the assets into ./dist which can then be deployed using a web server, CDN or the built-in Node server with yarn start. For more info on all of this, take a look at the Developing Docs. To build your own Docker container from the modified app, see Building your Own Container

⬆️ Back to Top


Building your Own Container#

Similar to above, you'll first need to fork and clone Dashy to your local system, and then install dependencies.

Then, either use Dashy's default Dockerfile as is, or modify it according to your needs.

To build and deploy locally, first build the app with: docker build -t dashy ., and then start the app with docker run -p 8080:80 --name my-dashboard dashy. Or modify the docker-compose.yml file, replacing image: lissy93/dashy with build: . and run docker compose up.

Your container should now be running, and will appear in the list when you run docker container ls –a. If you'd like to enter the container, run docker exec -it [container-id] /bin/ash.

You may wish to upload your image to a container registry for easier access. Note that if you choose to do this on a public registry, please name your container something other than just 'dashy', to avoid confusion with the official image. +You can push your build image, by running: docker push ghcr.io/OWNER/IMAGE_NAME:latest. You will first need to authenticate, this can be done by running echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin, where CR_PAT is an environmental variable containing a token generated from your GitHub account. For more info, see the Container Registry Docs.

⬆️ Back to Top


+ \ No newline at end of file diff --git a/docs/multi-language-support/index.html b/docs/multi-language-support/index.html index 44f578ce..45ea213a 100644 --- a/docs/multi-language-support/index.html +++ b/docs/multi-language-support/index.html @@ -6,7 +6,7 @@ Internationalization | Dashy - + @@ -16,7 +16,7 @@ If your language is a specific dialect or regional translation, then use the Pos E.g. import de from '@/assets/locales/de.json';

Second, add it to the array of languages, e.g:

export const languages = [  {    name: 'English',    code: 'en',    locale: en,    flag: '🇬🇧',  },  {    name: 'German', // The name of your language    code: 'de', // The ISO code of your language    locale: de, // The name of the file you imported (no quotes)    flag: '🇩🇪', // An optional flag emoji  },];

You can also add your new language to the readme, under the Language Switching section and optionally include your name/ username if you'd like to be credited for your work. Done!

If you are not comfortable with making pull requests, or do not want to modify the code, then feel free to instead send the translated file to me, and I can add it into the application. I will be sure to credit you appropriately.


Adding New Text to a Component#

If you're working on a new component, then any text that is displayed to the user should be extracted out of the component, and stored in the file. This also applies to any existing components, that might have been forgotten to be translated. Thankfully, everything is already setup, so this is a pretty easy job.

1. Add Translated Text#

Firstly, go to ./src/assets/locales/en.json, and either find the appropriate section, or create a new section. Lets say you're new component is called my-widget, you could add "my-widget": {} to store all your text as key-value-pairs. E.g.

"my-widget": {    "awesome-text": "I am some text, that will be seen by the user"}

Note that you must add English translations for all text. Missing languages are not a problem, as they will always fallback to English, but if the English is missing, then nothing can be displayed.

2. Use Text within Component#

Once your text is in the translation file, you can now use it within your component. There is a global $t function, with takes the key of your new translation, and returns the value. For example:

<p>{{ $t('my-widget.awesome-text') }}</p>

Note that the {{ }} just tells Vue that this is JavaScript/ dynamic. This will render: <p>I am some text, that will be seen by the user</p>

If you need to display text programmatically, from within the components JavaScript (e.g. in a toast popup), then use this.$t. For example: alert(this.$t('my-widget.awesome-text')).

You may also need to pass a variable to be displayed within a translation. Vue I18n supports Interpolations using mustache-like syntax.

For example, you would set your translation to:

{    "welcome-message": "Hello {name}!"}

And then pass that variable (name) within a JSON object as the second parameter on $t, like:

$t('welcome-message', { name: 'Alicia' })

Which will render:

Hello Alicia!

There are many other advanced features, including Pluralization, Datetime & Number Formatting, Message Support and more, all of which are outlined in the Vue-i18n Docs.

Basic Example#

Using the search bar as an example, this would look something like:

In ./src/components/Settings/SearchBar.vue:

<template>  <form>    <label for="search-input">{{ $t('search.search-label') }}</label>    <input      v-model="searchValue"      :placeholder="$t('search.search-placeholder')"    />  </form></template>

Then in ./src/assets/locales/en.json:

{"search": {    "search-label": "Search",    "search-placeholder": "Start typing to filter",  },  ...}
- + \ No newline at end of file diff --git a/docs/pages-and-sections/index.html b/docs/pages-and-sections/index.html index 51568337..fb2ca02b 100644 --- a/docs/pages-and-sections/index.html +++ b/docs/pages-and-sections/index.html @@ -6,14 +6,14 @@ Pages and Sections | Dashy - +

Pages and Sections

Multi-Page Support#

You can have additional pages within your dashboard, with each having it's own config file. The config files for sub-pages can either be stored locally, or hosted separately. A link to each additional page will be displayed in the navigation bar.

You can edit additional pages using the interactive editor, exactly the same was as your primary page (so long as it's local). But please save changes to one page, before you start editing the next.

Using Local Sub-Pages#

To get started, create a new .yml config file for your sub-page, placing it within /app/public. Then within your primary conf.yml, choose a name, and specify the path to the new file.

For example:

pages:- name: Networking Services  path: 'networking.yml'- name: Work Stuff  path: 'work.yml'

If you're sub-page is located within /app/public, then you only need to specify the filename, but if it's anywhere else, then the full path is required.

Using Remote Sub-Pages#

Config files don't need to be local, you can store them anywhere, and data will be imported as sub-pages on page load.

For example:

pages:- name: Getting Started  path: 'https://snippet.host/tvcw/raw'- name: Homelab  path: 'https://snippet.host/tetp/raw'- name: Browser Startpage  path: 'https://snippet.host/zcom/raw'

There are many options of how this can be used. You could store your config within a Git repository, in order to easily track and rollback changes. Or host your config on your NAS, to have it backed up with the rest of your files. Or use a hosted paste service, for example snippet.host, which supports never-expiring CORS-enabled pastes, which can also be edited later.

You will obviously not be able to write updates to remote configs directly through the UI editor, but you can still make and preview changes, then use the export menu to get a copy of the new config, which can then be pasted to the remote source manually. The config file must, of course be accessible from within Dashy. If your config contains sensitive info (like API keys, credentials, secret URLs, etc), take care not to expose it to the internet.

The following example shows creating a config, publishing it as a Gist, copying the URL to the raw file, and using it within your dashboard.

Public config in a gist demo

Restrictions#

Only top-level fields supported by sub-pages are pageInfo and sections. The appConfig and pages will always be inherited from your main conf.yml file. Other than that, sub-pages behave exactly the same as your default view, and can contain sections, items, widgets and page info like nav links, title and logo.

Note that since page paths are required by the router, they are set at build-time, not run-time, and so a rebuild (happens automatically) is required for changes to page paths to take effect (this only applies to changes to the pages array, rebuild isn't required for editing page content).

Sub-Items#

A normal section will contain zero or more items, for example:

- name: Coding  icon: far fa-code  items:  - title: GitHub    url: https://github.com/  - title: StackOverflow    url: http://stackoverflow.com/

But items can also be grouped together, referred to as sub-items. This is useful for a group of less frequently used items, which you don't want to take up too much space, or for action buttons (coming soon).

Item groups may also have an optional title.

- name: Coding  icon: far fa-code  items:  - title: Normal Item 1  - title: Normal Item 2  - subItems:    - title: JavaScript      url: https://developer.mozilla.org      icon: si-javascript    - title: TypeScript      url: https://www.typescriptlang.org/docs      icon: si-typescript    - title: Svelt      url: https://svelte.dev/docs      icon: si-svelte    - title: Go      url: https://go.dev/doc      icon: si-go
- + \ No newline at end of file diff --git a/docs/privacy/index.html b/docs/privacy/index.html index 46554125..8441bc9f 100644 --- a/docs/privacy/index.html +++ b/docs/privacy/index.html @@ -6,14 +6,14 @@ Privacy & Security | Dashy - +

Privacy & Security

Dashy was built with privacy in mind. Self-hosting your own apps and services is a great way to protect yourself from the mass data collection employed by big tech companies, and Dashy was designed to make self-hosting easier, by keeping your local services organized and accessible from a single place. The management docs contains a though guide on the steps you can take to secure your homelab.

Dashy operates on the premise, that no external data requests should ever be made, unless explicitly enabled by the user. In the interest of transparency, the code is 100% open source and clearly documented throughout.

🔐 For privacy and security tips, check out another project of mine: Personal Security Checklist

Contents#


External Requests#

By default, Dashy will not make any external requests, unless you configure it to. Some features (which are off by default) do require internat access, and this section outlines those features, the services used, and links to their privacy policies.

The following section outlines all network requests that are made when certain features are enabled.

Icons#

Font Awesome#

If either any of your sections, items or themes are using icons from font-awesome, then it will be automatically enabled. But you can also manually enable or disable it by setting appConfig.enableFontAwesome to true / false. Requests are made directly to Font-Awesome CDN, for more info, see the Font Awesome Privacy Policy.

Material Design Icons#

If either any of your sections, items or themes are mdi icons, then it will be automatically enabled. But you can also manually enable or disable it by setting appConfig.enableMaterialDesignIcons to true / false. Requests are made directly to Material-Design-Icons CDN, for more info, see the Material Design Icons Website.

Favicon Fetching#

If an item's icon is set to favicon, then it will be auto-fetched from the corresponding URL. Since not all websites have their icon located at /favicon.ico, and if they do, it's often very low resolution (like 16 x 16 px). Therefore, the default behavior is for Dashy to check if the URL is public, and if so will use an API to fetch the favicon. For self-hosted services, the favicon will be fetched from the default path, and no external requests will be made.

The default favicon API is allesedv.com, but this can be changed by setting appConfig.faviconApi to an alternate source (iconhorse, clearbit, faviconkit, besticon, duckduckgo, google and allesedv are supported). If you do not want to use any API, then you can set this property to local, and the favicon will be fetched from the default path. For hosted services, this will still incur an external request.

Generative Icons#

If an item has the icon set to generative, then an external request it made to Dice Bear to fetch the uniquely generated icon. The URL of a given service is used as the key for generating the icon, but it is first hashed and encoded for basic privacy. For more info, please reference the Dicebear Privacy Policy

As a fallback, if Dicebear fails, then Evatar is used.

Other Icons#

Section icons, item icons and app icons are able to accept a URL to a raw image, if the image is hosted online then an external request will be made. To avoid the need to make external requests for icon assets, you can either use a self-hosted CDN, or store your images within ./public/item-icons (which can be mounted as a volume if you're using Docker).

Web Assets#

By default, all assets required by Dashy come bundled within the source, and so no external requests are made. If you add an additional font, which is imported from a CDN, then that will incur an external request. The same applies for other web assets, like external images, scripts or styles.


Features#

Status Checking#

The status checking feature allows you to ping your apps/ services to check if they are currently operational.

Dashy will ping your services directly, and does not rely on any third party. If you are checking the uptime status of a public/ hosted application, then please refer to that services privacy policy. For all self-hosted services, requests happen locally within your network, and are not external.

Update Checks#

When the application loads, it checks for updates. The results of which are displayed in the config menu of the UI. This was implemented because using a very outdated version of Dashy may have unfixed issues. Your version is fetched from the source (local request), but the latest version is fetched from GitHub, which is an external request. This can be disabled by setting appConfig.disableUpdateChecks: true

Cloud Backup#

Dashy has an optional End-to-End encrypted cloud backup feature. No data is ever transmitted unless you actively enable this feature through the UI.

All data is encrypted before being sent to the backend. This is done in CloudBackup.js, using crypto.js's AES method, using the users chosen password as the key. The data is then sent to a Cloudflare worker (a platform for running serverless functions), and stored in a KV data store.

Your selected password never leaves your device, and is hashed before being compared. It is only possible to restore a configuration if you have both the backup ID and decryption password. Because the data is encrypted on the client-side (before being sent to the cloud), it is not possible for a man-in-the-middle, government entity, website owner, or even Cloudflare to be able read any of your data.

Web Search#

Dashy has a primitive web search feature. No external requests are made, instead you are redirected to your chosen search engine (defaults to DuckDuckGo), using your chosen opening method.

This feature can be disabled under appConfig, with webSearch: { disableWebSearch: true }

Anonymous Error Reporting#

Error reporting is disabled by default, and no data will ever be sent without your explicit consent. In fact, the error tracking code isn't even imported unless you have actively enabled it. Sentry is used for this, it's an open source error tracking and performance monitoring tool, used to identify any issues which occur in the production app (if you enable it).

The crash report includes the file or line of code that triggered the error, and a 2-layer deep stack trace. Reoccurring errors will also include the following user information: OS type (Mac, Windows, Linux, Android or iOS) and browser type (Firefox, Chrome, IE, Safari). Data scrubbing is enabled. IP address will not be stored. If any potentially identifiable data ever finds its way into a crash report, it will be automatically and permanently erased. All statistics collected are anonymized and stored securely, and ae automatically deleted after 14 days. For more about privacy and security, see the Sentry Docs.

Enabling anonymous error reporting helps me to discover bugs I was unaware of, and then fix them, in order to make Dashy more reliable long term. Error reporting is activated by setting appConfig.enableErrorReporting: true.

If you need to monitor bugs yourself, then you can self-host your own Sentry Server, and use it by setting appConfig.sentryDsn to your Sentry instances Data Source Name, then just enable error reporting in Dashy.


Themes#

Certain themes may use external assets (such as fonts or images). Currently, this only applies the Adventure theme.


Widgets#

Dashy supports Widgets for displaying dynamic content. Below is a list of all widgets that make external data requests, along with the endpoint they call and a link to the Privacy Policy of that service.


Browser Storage#

In order for user preferences to be persisted between sessions, certain data needs to be stored in the browsers local storage. No personal info is kept here, none of this data can be accessed by other domains, and no data is ever sent to any server without your prior consent.

You can view and delete stored data by opening up the dev tools: F12 --> Application --> Storage.

The following section outlines all data that is stored in the browsers, as cookies, session storage or local storage.

Cookies#

Cookies will expire after their pre-defined lifetime

  • AUTH_TOKEN - A unique token, generated from a hash of users credentials, to verify they are authenticated. Only used when auth is enabled.

Session Storage#

Session storage is deleted when the current session ends (tab / window is closed)

  • SW_STATUS - The current status of any service workers
  • ERROR_LOG - List of recent errors

Local Storage#

Local storage is persisted between sessions, and only deleted when manually removed

  • LANGUAGE - The locale to show app text in
  • HIDE_WELCOME_BANNER - Set to true once user dismissed welcome message, so that it's not shown again
  • LAYOUT_ORIENTATION - Preferred section layout, either horizontal, vertical or auto
  • COLLAPSE_STATE - Remembers which sections are collapsed
  • ICON_SIZE - Size of items, either small, medium or large
  • THEME - Users applied theme
  • CUSTOM_COLORS - Any color modifications made to a given theme
  • BACKUP_ID - If a backup has been made, the ID is stored here
  • BACKUP_HASH - A unique hash of the previous backups meta data
  • HIDE_SETTINGS - Lets user hide or show the settings menu
  • USERNAME - If user logged in, store username. Only used to show welcome message, not used for auth
  • CONF_SECTIONS - Array of sections, only used when user applies changes locally
  • PAGE_INFO - Config page info, only used when user applies changes locally
  • APP_CONFIG - App config, only used when user applies changes locally
  • MOST_USED - If smart sort is used to order items by most used, store open count
  • LAST_USED - If smart sort is used to order items by last used, store timestamps

Deleting Stored Data#

You can manually view and delete session storage, local storage and cookies at anytime. Fist open your browsers developer tools (usually F12), then under the Application tab select the storage category. Here you will see a list of stored data, and you can select any item and delete it.


Dependencies#

As with most web projects, Dashy relies on several dependencies. For links to each, and a breakdown of their licenses, please see Legal.

Dependencies can introduce security vulnerabilities, but since all these packages are open source any issues are usually very quickly spotted. Dashy is using Snyk for dependency security monitoring, and you can see the latest report here. If any issue is detected by Snyk, a note about it will appear at the top of the Readme, and will usually be fixed within 48 hours.

Note that packages listed under devDependencies section are only used for building the project, and are not included in the production environment.


Securing your Environment#

Running your self-hosted applications in individual, containerized environments (such as containers or VMs) helps keep them isolated, and prevent an exploit in one service effecting another.

If you're running Dashy in a container, see Management Docs --> Container Security for step-by-step security guide.

There is very little complexity involved with Dashy, and therefore the attack surface is reasonably small, but it is still important to follow best practices and employ monitoring for all your self-hosted apps. A couple of things that you should look at include:

  • Use SSL for securing traffic in transit
  • Configure authentication to prevent unauthorized access
  • Keep your system, software and Dashy up-to-date
  • Ensure your server is appropriately secured
  • Manage users and SSH correctly
  • Enable and configure firewall rules
  • Implement security, malware and traffic scanning
  • Setup malicious traffic detection
  • Understand the Docker attack fronts, and follow Docker Security Best Practices

This is covered in more detail in App Management.


Security Features#

Subresource Integrity#

Subresource Integrity or SRI is a security feature that enables browsers to verify that resources they fetch are delivered without unexpected manipulation. It works by allowing you to provide a cryptographic hash that a fetched resource must match. This prevents the app from loading any resources that have been manipulated, by verifying the files hashes. It safeguards against the risk of an attacker injecting arbitrary malicious content into any files served up via a CDN.

Dashy supports SRI, and it is recommended to enable this if you are hosting your dashboard via a public CDN. To enable SRI, set the INTEGRITY environmental variable to true.

SSL#

Native SSL support is enabled, for setup instructions, see the Management Docs

Authentication#

Dashy supports both basic auth, as well as server-based SSO using Keycloak. Full details of which, along with alternate authentication methods can be found in the Authentication Docs. If your dashboard is exposed to the internet and/ or contains any sensitive info it is strongly recommended to configure access control with Keycloak or another server-side method.


Disabling Features#

You may wish to disable features that you don't want to use, if they involve storing data in the browser or making network requests.

  • To disable smart-sort (uses local storage), set appConfig.disableSmartSort: true
  • To disable update checks (makes external request to GH), set appConfig.disableUpdateChecks: true
  • To disable web search (redirect to external / internal content), set appConfig.disableWebSearch: true
  • To keep status checks disabled (external/ internal requests), set appConfig.statusCheck: false
  • To keep font-awesome icons disabled (external requests), set appConfig.enableFontAwesome: false
  • To keep error reporting disabled (external requests and data collection), set appConfig.enableErrorReporting: false
  • To keep the service worker disabled (stores cache of app in browser data), set appConfig.enableServiceWorker: false

Reporting a Security Issue#

If you think you've found a critical issue with Dashy, please send an email to security@mail.alicia.omg.lol. You can encrypt it, using 0688 F8D3 4587 D954 E9E5 1FB8 FEDB 68F5 5C02 83A7. You should receive a response within 48 hours. For more information, see SECURITY.md.

All non-critical issues can be raised as a ticket.

Please include the following information:

  • Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
  • Full paths of source file(s) related to the manifestation of the issue
  • The location of the affected source code (tag/branch/commit or direct URL)
  • Any special configuration required to reproduce the issue
  • Step-by-step instructions to reproduce the issue
  • Proof-of-concept or exploit code (if possible)
  • Impact of the issue, including how an attacker might exploit the issue
- + \ No newline at end of file diff --git a/docs/quick-start/index.html b/docs/quick-start/index.html index 595edf46..f95ed2ff 100644 --- a/docs/quick-start/index.html +++ b/docs/quick-start/index.html @@ -6,7 +6,7 @@ Quick Start | Dashy - + @@ -15,7 +15,7 @@ If you don't want to use Docker, then you can use one of Dashy's other supported installation methods instead, all of which are outlined in the Deployment Docs.


2. Installation#

To pull the latest image, and build and start the app run:

docker run -d \  -p 8080:80 \  -v ~/my-conf.yml:/app/public/conf.yml \  --name my-dashboard \  --restart=always \  lissy93/dashy:latest

Either replace the -v path to point to your config file, or leave it out. For a full list of available options, then see Dashy with Docker Docs. If you'd prefer to use Docker Compose, then see Dashy with Docker Compose Docs. Alternate registries, architectures and pinned versions are also supported.

Your dashboard should now be up and running at http://localhost:8080 (or your servers IP address/ domain, and the port that you chose). The first time you build, it may take a few minutes.


3. Configure#

Now that you've got Dashy running, you are going to want to set it up with your own content. Config is written in YAML Format, and saved in /public/conf.yml. The format on the config file is pretty straight forward. There are three root attributes:

  • pageInfo - Dashboard meta data, like title, description, nav bar links and footer text
  • appConfig - Dashboard settings, like themes, authentication, language and customization
  • sections - An array of sections, each including an array of items

You can view a full list of all available config options in the Configuring Docs.

pageInfo:  title: Home Labsections: # An array of sections- name: Example Section  icon: far fa-rocket  items:  - title: GitHub    description: Dashy source code and docs    icon: fab fa-github    url: https://github.com/Lissy93/dashy  - title: Issues    description: View open issues, or raise a new one    icon: fas fa-bug    url: https://github.com/Lissy93/dashy/issues- name: Local Services  items:  - title: Firewall    icon: favicon    url: http://192.168.1.1/  - title: Game Server    icon: https://i.ibb.co/710B3Yc/space-invader-x256.png    url: http://192.168.130.1/

Notes:

  • You can use a Docker volume to pass a config file from your host system to the container
    • E.g. -v ./host-system/my-local-conf.yml:/app/public/conf.yml
  • It's also possible to edit your config directly through the UI, and changes will be saved in this file
  • Check your config against Dashy's schema, with docker exec -it [container-id] yarn validate-config
  • You might find it helpful to look at some examples, a collection of which can be found here
  • After editing your config, the app will rebuild in the background, which may take a minute

4. Further Customisation#

Once you've got Dashy setup, you'll want to ensure the container is properly healthy, secured, backed up and kept up-to-date. All this is covered in the Management Docs.

You might also want to check out the docs for specific features you'd like to use:

  • Authentication - Setting up authentication to protect your dashboard
  • Alternate Views - Using the startpage and workspace view
  • Backup & Restore - Guide to Dashy's cloud sync feature
  • Icons - Outline of all available icon types for sections and items
  • Localisation - How to change language, or add your own
  • Status Indicators - Using Dashy to monitor uptime and status of your apps
  • Search & Shortcuts - Using instant filter, web search and custom hotkeys
  • Theming - Complete guide to applying, writing and modifying themes and styles

5. Final Note#

If you need any help or support in getting Dashy running, head over to the Discussions page. If you think you've found a bug, please do raise it so it can be fixed. For contact options, see the Support Page.

If you're enjoying Dashy, and have a few minutes to spare, please do take a moment to look at the Contributing Page. Huge thanks to everyone who has already helped out!

Enjoy your dashboard :)


Alternative Deployment Method 1 - From Source#

You can also easily run the app on your system without Docker. For this Git, Node.js, and Yarn are required.

git clone https://github.com/Lissy93/dashy.git && cd dashyyarn # Install dependenciesyarn build # Build the appyarn start # Start the app

Then edit ./public/conf.yml and rebuild the app with yarn build


Alternative Deployment Method 2 - Netlify#

Don't have a server? No problem! You can run Dashy for free on Netlify (as well as many other cloud providers). All you need it a GitHub account.

  1. Fork Dashy's repository on GitHub
  2. Log in to Netlify with GitHub
  3. Click "New site from Git" and select your forked repo, then click Deploy!
  4. You can then edit the config in ./public/conf.yml in your repo, and Netlify will rebuild the app

Alternative Deployment Method 3 - Cloud Services#

Dashy supports 1-Click deployments on several popular cloud platforms. To spin up a new instance, just click a link below:

- + \ No newline at end of file diff --git a/docs/readme/index.html b/docs/readme/index.html index 9c5bbc7b..fd12532b 100644 --- a/docs/readme/index.html +++ b/docs/readme/index.html @@ -6,13 +6,13 @@ ![Dashy Docs](https://i.ibb.co/4mdNf7M/heading-docs.png) | Dashy - +

Dashy Docs

Running Dashy#

  • Quick Start - TLDR guide on getting Dashy up and running
  • Deployment - Full guide on deploying Dashy either locally or online
  • Configuring - Complete list of all available options in the config file
  • App Management - Managing your app, updating, security, web server configuration, etc
  • Troubleshooting - Common errors and problems, and how to fix them

Development and Contributing#

  • Developing - Running Dashy development server locally, and general workflow
  • Development Guides - Common development tasks, to help new contributors
  • Contributing - How you can help keep Dashy alive
  • Showcase - See how others are using Dashy, and share your dashboard
  • Credits - List of people and projects that have made Dashy possible
  • Release Workflow - Info about releases, CI and automated tasks

Feature Docs#

  • Authentication - Guide to setting up authentication to protect your dashboard
  • Alternate Views - Outline of available pages / views and item opening methods
  • Backup & Restore - Guide to backing up config with Dashy's cloud sync feature
  • Icons - Outline of all available icon types for sections and items, with examples
  • Language Switching - Details on how to switch language, or add a new locale
  • Pages and Sections - Multi-page support, sections, items and sub-items
  • Status Indicators - Using Dashy to monitor uptime and status of your apps
  • Searching & Shortcuts - Searching, launching methods + keyboard shortcuts
  • Theming - Complete guide to applying, writing and modifying themes + styles
  • Widgets - List of all dynamic content widgets, with usage guides and examples

Misc#

- + \ No newline at end of file diff --git a/docs/release-workflow/index.html b/docs/release-workflow/index.html index ab518c62..34bb7eff 100644 --- a/docs/release-workflow/index.html +++ b/docs/release-workflow/index.html @@ -6,14 +6,14 @@ Releases and Workflows | Dashy - +

Releases and Workflows

Release Schedule#

We're using Semantic Versioning, to indicate major, minor and patch versions. You can find the current version number in the readme, and check your apps version under the config menu. The version number is pulled from the package.json file.

Typically there is a new major release every 2 weeks, usually on Sunday, and you can view these under the Releases Page. Each new version will also have a corresponding tag on GitHub, and each major release will also result in the creation of a new tag on DockerHub, so that you can fix your container to a certain version.

For a full breakdown of each change, you can view the Changelog. Each new feature or significant change needs to be submitted through a pull request, which makes it easy to review and track these changes, and roll back if needed.


Deployment Process#

All changes and new features are submitted as pull requests, which can then be tested, reviewed and (hopefully) merged into the master branch. Every time there is a change in the major version number, a new release is published. This usually happens every 2 weeks, on a Sunday.

When a PR is opened:

  • The feature branch is built, and deployed as a Netlify instance. This can be accessed at: https://deploy-preview-[pr-number]--dashy-dev.netlify.app, and this URL as well as a link to the build logs are added as a comment on the PR by Netlify bot
  • Depending on what files were modified, the bot may also add a comment to remind the author of useful info
  • A series of checks will run on the new code, using GH Actions, and prevent merging if they fail. This includes: linting, testing, code quality and complexity checking, security scanning and a spell check
  • If a new dependency was added, liss-bot will comment with a summary of those changes, as well as the cost of the module, version, and any security concerns. If the bundle size has increased, this will also be added as a comment

After the PR is merged:

  • The app is build, and deployed to: https://dev.dashy.to
  • A new tag in GitHub is created, using the apps version number (from the package.json)
  • The Docker container is built, and published under the :latest tag on DockerHub and GHCR

When a new major version is released:

  • A new GitHub release is created and published, under new versions tag, with info from the changelog
  • The container is built and published under a new tag will be created on DockerHub, called :release-[version]
  • An announcement is opened in GitHub discussions, outlining the main changes, where users can comment and ask questions

Netlify Status


Git Strategy#

Git Flow#

Like most Git repos, we are following the Github Flow standard.

  1. Create a branch (or fork if you don'd have write access)
  2. Code some awesome stuff, then add and commit your changes
  3. Create a Pull Request, complete the checklist and ensure the build succeeds
  4. Follow up with any reviews on your code
  5. Merge 🎉

Git Branch Naming#

The format of your branch name should be something similar to: [TYPE]/[TICKET]_[TITLE] For example, FEATURE/420_Awesome-feature or FIX/690_login-server-error

Commit Emojis#

Using a single emoji at the start of each commit message, to indicate the type task, makes the commit ledger easier to understand, plus it looks cool.

  • 🎨 :art: - Improve structure / format of the code.
  • ⚡️ :zap: - Improve performance.
  • 🔥 :fire: - Remove code or files.
  • 🐛 :bug: - Fix a bug.
  • 🚑️ :ambulance: - Critical hotfix
  • :sparkles: - Introduce new features.
  • 📝 :memo: - Add or update documentation.
  • 🚀 :rocket: - Deploy stuff.
  • 💄 :lipstick: - Add or update the UI and style files.
  • 🎉 :tada: - Begin a project.
  • :white_check_mark: - Add, update, or pass tests.
  • 🔒️ :lock: - Fix security issues.
  • 🔖 :bookmark: - Make a Release or Version tag.
  • 🚨 :rotating_light: - Fix compiler / linter warnings.
  • 🚧 :construction: - Work in progress.
  • ⬆️ :arrow_up: - Upgrade dependencies.
  • 👷 :construction_worker: - Add or update CI build system.
  • ♻️ :recycle: - Refactor code.
  • 🩹 :adhesive_bandage: - Simple fix for a non-critical issue.
  • 🔧 :wrench: - Add or update configuration files.
  • 🍱 :bento: - Add or update assets.
  • 🗃️ :card_file_box: - Perform database schema related changes.
  • ✏️ :pencil2: - Fix typos.
  • 🌐 :globe_with_meridians: - Internationalization and translations.

For a full list of options, see gitmoji.dev

PR Guidelines#

Once you've made your changes, and pushed them to your fork or branch, you're ready to open a pull request!

For a pull request to be merged, it must:

  • Must be backwards compatible
  • The build, lint and tests (run by GH actions) must pass
  • There must not be any merge conflicts

When you submit your PR, include the required info, by filling out the PR template. Including:

  • A brief description of your changes
  • The issue, ticket or discussion number (if applicable)
  • For UI relate updates include a screenshot
  • If any dependencies were added, explain why it was needed, state the cost associated, and confirm it does not introduce any security issues
  • Finally, check the checkboxes, to confirm that the standards are met, and hit submit!

Automated Workflows#

Dashy makes heavy use of GitHub Actions to fully automate the checking, testing, building, deploying of the project, as well as administration tasks like management of issues, tags, releases and documentation. The following section outlines each workflow, along with a link the the action file, current status and short description. A lot of these automations were made possible using community actions contributed to GH marketplace by some amazing people.

Code Processing#

ActionDescription
Code Linter
code-linter.yml
After a pull request is created, all new code changes will be linted, and the CI will fail with a helpful message if the code has any formatting inconsistencies
Code Spell Check
code-spell-check.yml
After a PR submitted, all auto-fixable spelling errors will be detected, then Liss-Bot will create a separate PR to propose the fixes
Dependency Update Summary
dependency-updates-summary.yml
After a PR is submitted, if any of the dependencies are modified, then Liss-Bot will add a comment, explaining which packages have been added, removed, updated or downgraded, as well as other helpful info
Get Size
get-size.yml
Adds comment to PR if the size of the built + bundled application has changed compared to the previous version
Security Scan
security-scanning.yml
Uses Snyk to scan the code and dependencies after a PR. Will add a comment and cause the build to fail if a new vulnerability or potential issue is present

Releases#

ActionDescription
Create Tag
auto-tag-pr.yml
Whenever the version indicated in package.json is updates, a new GitHub tag will be created for that point in time
Build App
build-app.yml
After changes are merged into the master branch, the app will be build, with output pushed to the dev-demo branch
Cache Artifacts
cache-artifacts.yml
After build, returned files will be cached for future actions for that commit
Docker Publish
docker-publish.yml
After PR is merged, the multi-architecture Docker container will be built, and then published to GHCR

Issue Management#

ActionDescription
Close Incomplete Issues
close-incomplete-issues.yml
Issues which do not match any of the issue templates will be closed, and a comment posted explaining why
Close Stale Issues
close-stale-issues.yml
Issues which have not been updated for 6 weeks will have a comment posted to them. If the author does not reply within the next week, then the issue will be marked as stale and closed. The original author may still reopen the issue at any time
Close Potential Spam Issues
issue-spam-control.yml
Auto-closes issues, and adds a comment if it was submitted by a user who hasn't yet interacted with the repo, is new to GitHub and has not starred the repository. The comment will advise them to check their issue is complete, and then allow them to reopen it
Issue Translator
issue-translator.yml
Auto-translates any comments and issues that were written in any language other than English, and posts the translation as a comment below
Label Sponsors
label-sponsors.yml
Adds a special label to any issues or pull requests raised by users who are sponsoring the project via GitHub, so that they can get priority support
LGTM Comment
lgtm-comment.yml
When a PR review contains the words LGTM (looks good to me), the Liss-Bot will reply with a random celebratory or thumbs up GIF, just as a bit of fun
Mind your Language
mind-your-language.yml
Replies to any comment (on issue or PR) that contains profanities, offensive or inappropriate language with a polite note reminding the user of the code of conduct
Release Notifier
release-commenter.yml
Once a release has been published which fixes an issue, a comment will be added to the relevant issues informing the user who raised it that it was fixed in the current release
Update Issue after Merge
update-issue-after-pr.yml
After a PR which fixes an issue is merged, Liss-Bot will add a comment to said issue based on the git commit message
Auto Add Comment Based on Tag
add-comment-from-tag.yml
Will add comment with useful info to certain issues, based on the tag applied

PR Management#

ActionDescription
PR Commenter
pr-commenter.yml
Adds comment with helpful info to pull requests, based on which files have been changes
Issue from Todo Code
raise-issue-from-todo.yml
When a todo note is found in the code after a PR, then Liss-Bot will automatically raise an issue, so that the todo can be addressed/ implemented. The issue will be closed once the todo has been implemented or removed

Documentation & Reports#

ActionDescription
Generate Credits
generate-credits.yml
Generates a report, including contributors, collaborators, sponsors, bots and helpful users. Will then insert a markdown table with thanks to these GitHub users and links to their profiles into the Credits page, as well as a summary of sponsors and top contributors into the main readme
Wiki Sync
wiki-sync.yml
Generates and publishes the repositories wiki page using the markdown files within the docs directory

- + \ No newline at end of file diff --git a/docs/searching/index.html b/docs/searching/index.html index 1f505c28..3531edd9 100644 --- a/docs/searching/index.html +++ b/docs/searching/index.html @@ -6,7 +6,7 @@ Keyboard Shortcuts | Dashy - + @@ -14,7 +14,7 @@

Keyboard Shortcuts

Searching#

One of the primary purposes of Dashy is to allow you to quickly find and launch a given app. To make this as quick as possible, there is no need to touch the mouse, or press a certain key to begin searching - just start typing. Results will be filtered in real-time. No need to worry about case, special characters or small typos, these are taken care of, and your results should appear.

Navigating#

You can navigate through your items or search results using the keyboard. You can use Tab to cycle through results, and Shift + Tab to go backwards. Or use the arrow keys, , , and .

Launching Apps#

You can launch a elected app by hitting Enter. This will open the app using your default opening method, specified in target (either newtab, sametab, modal, top or workspace). You can also use Alt + Enter to open the app in a pop-up modal, or Ctrl + Enter to open it in a new tab. For all available opening methods, just right-click on an item, to bring up the context menu.

Tags#

By default, items are filtered by the title attribute, as well as the hostname (extracted from url), the provider and description. If you need to find results based on text which isn't included in these attributes, then you can add tags to a given item.

  items:  - title: Plex    description: Media library    icon: favicon    url: https://plex.lab.local    tags: [ movies, videos, music ]  - title: FreshRSS    description: RSS Reader    icon: favicon    url: https://freshrss.lab.local    tags: [ news, updates, blogs ]
 

In the above example, Plex will be visible when searching for 'movies', and FreshRSS with 'news'

Custom Hotkeys#

For apps that you use regularly, you can set a custom keybinding. Use the hotkey parameter on a certain item to specify a numeric key, between 0 - 9. You can then launch that app, by just pressing that key, which is much quicker than searching for it, if it's an app you use frequently.

- title: Bookstack  icon: far fa-books  url: https://bookstack.lab.local/  hotkey: 2- title: Git Tea  icon: fab fa-git  url: https://git.lab.local/  target: workspace  hotkey: 3

In the above example, pressing 2 will launch Bookstack. Or hitting 3 will open Git in the workspace view.

Web Search#

It's possible to search the web directly from Dashy, which might be useful if you're using Dashy as your start page. This can be done by typing your query as normal, and then pressing . Web search options are configured under appConfig.webSearch.

Setting Search Engine#

Set your default search engine using the webSearch.searchEngine property. This defaults to DuckDuckGo. Search engine must be referenced by their key, the following providers are supported:

Using Custom Search Engine#

You can also use a custom search engine, that isn't included in the above list (like a self-hosted instance of Whoogle or Searx). Set searchEngine: custom, and then specify the URL (plus query params) to you're search engine under customSearchEngine.

For example:

appConfig:  webSearch:    searchEngine: custom    customSearchEngine: 'https://searx.local/search?q='

Setting Opening Method#

In a similar way to opening apps, you can specify where you would like search results to be opened. This is done under the openingMethod attribute, and can be set to either newtab, sametab or workspace. By default results are opened in a new tab.

Using Bangs#

An insanely useful feature of DDG is Bangs, where you type a specific character combination at the start of your search query, and it will be redirected the that website, such as '!w Docker' will display the Docker wikipedia page. Dashy has a similar feature, enabling you to define your own custom bangs to redirect search results to a specific app, website or search engine.

This is done under the searchBangs property, with a list of key value pairs. The key is what you will type, and the value is the destination, either as an identifier or a URL with query parameters.

For example:

appConfig:  webSearch:    searchEngine: 'duckduckgo'    openingMethod: 'newtab'    searchBangs:      /r: reddit      /w: wikipedia      /s: https://whoogle.local/search?q=      /a: https://www.amazon.co.uk/s?k=      ':wolf': wolframalpha      ':so': stackoverflow      ':git': github

Note that bangs begging with ! or : must be surrounded them in quotes

Disabling Web Search#

Web search can be disabled, by setting disableWebSearch, for example:

appConfig:  webSearch: { disableWebSearch: true }

Clearing Search#

You can clear your search term at any time, resting the UI to it's initial state, by pressing Esc. This can also be used to close any open pop-up modals.

- + \ No newline at end of file diff --git a/docs/showcase/index.html b/docs/showcase/index.html index 66aa256b..d93af716 100644 --- a/docs/showcase/index.html +++ b/docs/showcase/index.html @@ -6,19 +6,19 @@ *Dashy Showcase* 🌟 | Dashy - +
-

Dashy Showcase 🌟

💗 Got a sweet dashboard? Submit it to the showcase! 👉 See How

Home Lab 2.0#

screenshot-homelab


Dipan's Dash#

By @Dipanghosh - dipan.de Re: #777

With the option of embedding iframes, it becomes possible to combine and conquer. I have set up Dashy to include graphs from grafana, and set them so that they update automatically. I also have uptime monitors from uptime Kuma, panels from homeassistant are also possible to be included.
+

Dashy Showcase 🌟

💗 Got a sweet dashboard? Submit it to the showcase! 👉 See How

MNDashboard#

By @mahrnet Re: #1491

screenshot-MNDashboard


Home Lab 2.0#

screenshot-homelab


Dipan's Dash#

By @Dipanghosh - dipan.de Re: #777

With the option of embedding iframes, it becomes possible to combine and conquer. I have set up Dashy to include graphs from grafana, and set them so that they update automatically. I also have uptime monitors from uptime Kuma, panels from homeassistant are also possible to be included.
Dashy is awesome!

screenshot-dipanghosh-dashboard


Ratty222#

By @ratty222 Re: #384

screenshot-ratty222-dashy


Hugalafutro Dashy#

By @hugalafutro Re: #505

hugalafutro-dashy-screenshot


NAS Home Dashboard#

By @cerealconyogurt Re: #74

screenshot-networking-services


Brewhack#

By @brpeterso Re: #680

screenshot-brewhack-dashboard


The Dragons Lair#

By dr460nf1r3 via #684

My new startpage featuring the stuff I use most. And of course dragons!

screenshot-dragons-lair


Homelab & VPS dashboard#

By @shadowking001 Re: #86

screenshot-shadowking001-dashy


Raspberry PI Docker Dashboard#

By @henkiewie Re: #622

I use this dashboard every day. It now even includes a player for a radio stream which I configured with Logitech media server and icecast. I made an smaller version of the grafana dashboard to fit an iframe in kiosk mode, so it monitors the most important values of my RPI. The PI is in Argon m2 case and used as a NAS. The dashboard is a copy of the adventure theme with some changes saved in /app/src/styles/user-defined-themes.scss

screenshot-henkiewie-dashy


First Week of Self-Hosting#

By u//RickyCZ via Reddit

screenshot-week-of-self-hosting


EVO Dashboard#

By @EVOTk Re: #316

screenshot-evo-dashboard


The Private Dashboard#

By @DylanBeMe Re: #419

screenshot-private-dashboard


Networking Services#

By @Lissy93

screenshot-networking-services


Dashy Live#

By @Lissy93

A dashboard I made to manage all project development links from one place. View demo at live.dashy.to.

screenshot-dashy-live


System Monitor#

An aggregated board for monitoring system resource usage from a single view

screenshot-monitor


Browser Startpage#

screenshot-startpage


CFT Toolbox#

screenshot-cft-toolbox


Bookmarks#

screenshot-bookmarks


Project Management#

screenshot-project-management


Dashy Example#

An example dashboard, by @Lissy93. View live at demo.dashy.to.

screenshot-dashy-example


HomeLAb 3.0#

By @skoogee (http://zhrn.cc) #279

Dashy, is the most complete dashboard I ever tried, has all the features, and it sets itself apart from the rest. It is my default homepage now. I am thankful to the developer @Lissy93 for sharing such a wonderful creation.

screenshot-12-skoogee-homelab-3


Ground Control#

By @dtctek Re: #83

screenshot-ground-control


Croco_Grievous#

By u/Croco_Grievous via reddit

screenshot-croco-grievous-dashy


Crypto Dash#

Example usage of widgets to monitor cryptocurrencies news, prices and data. Config is available here

screenshot-crypto-dash


Stefantigro#

By u/stefantigro via reddit

screenshot-stefantigro-dashy


Morning Dashboard#

Displayed on my smart screen between 05:00 - 08:00, and includes all the info that I usually check before leaving for work

screenshot-morning-dash


Yet Another Homelab#

screenshot-yet-another-homelab


Submitting your Dashboard#

How to Submit#

What to Include#

Please include the following information:

  • A single high-quality screenshot of your Dashboard
  • A short title (it doesn't have to be particularly imaginative)
  • An optional description, you could include details on anything interesting or unique about your dashboard, or say how you use it, and why it's awesome
  • Optionally leave your name or username, with a link to your GitHub, Twitter or Website

Template#

If you're submitting a pull request, please use a format similar to this:

### [Dashboard Name] (required)
 > Submitted by [@username](https://github.com/user) (optional)
 [An optional text description, or any interesting details] (optional)
 ![dashboard-screenshot](https://example.com/url-to-screenshot.png) (required)
 ---
-
- +
+ \ No newline at end of file diff --git a/docs/showcase/readme/index.html b/docs/showcase/readme/index.html index fa57dc73..4cdfdd90 100644 --- a/docs/showcase/readme/index.html +++ b/docs/showcase/readme/index.html @@ -6,13 +6,13 @@ readme | Dashy - + - + \ No newline at end of file diff --git a/docs/status-indicators/index.html b/docs/status-indicators/index.html index 77ac5835..d539da6a 100644 --- a/docs/status-indicators/index.html +++ b/docs/status-indicators/index.html @@ -6,14 +6,14 @@ Status Indicators | Dashy - +

Status Indicators

Dashy has an optional feature that can display a small icon next to each of your running services, indicating it's current status. This can be useful if you are using Dashy as your homelab's start page, as it gives you an overview of the health of each of your running services. The status feature will show response time, response code, online/ offline check and if applicable, a relevant error message.

Enabling Status Indicators#

By default, this feature is off. If you do not want this feature, just don't add the statusCheck to your conf.yml file, then no requests will be made.

To enable status checks, you can either turn it on for all items, by setting appConfig.statusCheck: true, like:

appConfig:  statusCheck: true

Or you can enable/ disable it on a per-item basis, with the item[n].statusCheck attribute

sections:- name: Firewall  items:  - title: OPNsense    description: Firewall Central Management    icon: networking/opnsense.png    url: https://192.168.1.1    statusCheck: false  - title: MalTrail    description: Malicious traffic detection system    icon: networking/maltrail.png    url: http://192.168.1.1:8338    statusCheck: true  - title: Ntopng    description: Network traffic probe and network use monitor    icon: networking/ntop.png    url: http://192.168.1.1:3001    statusCheck: true

Continuous Checking#

By default, with status indicators enabled Dashy will check an applications status on page load, and will not keep indicators updated. This is usually desirable behavior. However, if you do want the status indicators to continue to poll your running services, this can be enabled by setting the statusCheckInterval attribute. Here you define an interval as an integer in seconds, and Dashy will poll your apps every x seconds. Note that if this number is very low (below 5 seconds), you may notice the app running slightly slower.

The following example, will instruct Dashy to continuously check the status of your services every 20 seconds.

appConfig:  statusCheck: true  statusCheckInterval: 20

Using a Different Endpoint#

By default, the status checker will use the URL of each application being checked. In some situations, you may want to use a different endpoint for status checking. Similarly, some services provide a dedicated path for uptime monitoring.

You can set the statusCheckUrl property on any given item in order to do this. The status checker will then ping that endpoint, instead of the apps main url property.

Setting Custom Headers#

If your service is responding with an error, despite being up and running, it is most likely because custom headers for authentication, authorization or encoding are required. You can define these headers under the statusCheckHeaders property for any service. It should be defined as an object format, with the name of header as the key, and header content as the value. For example, statusCheckHeaders: { 'X-Custom-Header': 'foobar' }

Disabling Security#

By default, (if you're using HTTPS) any requests to insecure or non-HTTPS content will be blocked. This will cause the status check to fail. If you trust the endpoint (e.g. you're self-hosting it), then you can disable this security measure for an individual item. This is done by setting statusCheckAllowInsecure: true

Allowing Alternative Status Codes#

If you expect your service to return a status code that is not in the 2XX range, and still want the indicator to be green, then you can specify an expected status code under statusCheckAcceptCodes for a given item. For example, statusCheckAcceptCodes: '403,418'

Troubleshooting Failing Status Checks#

If you're using status checks, and despite a given service being online, the check is displaying an error, there are a couple of things you can look at:

If your service requires requests to include any authorization in the headers, then use the statusCheckHeaders property, as described above.

If you are still having issues, it may be because your target application is blocking requests from Dashy's IP. This is a CORS error, and can be fixed by setting the headers on your target app, to include:

Access-Control-Allow-Origin: https://location-of-dashy/Vary: Origin

If the URL you are checking has an unsigned certificate, or is not using HTTPS, then you may need to disable the rejection of insecure requests. This can be done by setting statusCheckAllowInsecure to true for a given item.

If your service is online, but responds with a status code that is not in the 2xx range, then you can use statusCheckAcceptCodes to set an accepted status code.

If you get an error, like Service Unavailable: Server resulted in a fatal error, even when it's definitely online, this is most likely caused by missing the protocol. Don't forget to include https:// (or whatever protocol) before the URL, and ensure that if needed, you've specified the port.

Running Dashy in HOST network mode, instead of BRIDGE will allow status check access to other services in HOST mode. For more info, see #445.

If you have firewall rules configured, then ensure that they don't prevent Dashy from making requests to the other services you are trying to access.

Currently, the status check needs a page to be rendered, so if this URL in your browser does not return anything, then status checks will not work. This may be modified in the future, but in the meantime, a fix would be to make your own status service, which just checks if your app responds with whatever code you'd like, and then return a 200 plus renders an arbitrary message. Then just point statusCheckUrl to your custom page.

For further troubleshooting, use an application like Postman to diagnose the issue. Set the parameter to GET, and then make a call to: https://[url-of-dashy]/status-check/?&url=[service-url]. Where the service URL must have first been encoded (e.g. with encodeURIComponent() or urlencoder.io)

If you're serving Dashy though a CDN, instead of using the Node server or Docker image, then the Node endpoint that makes requests will not be available to you, and all requests will fail. A workaround for this may be implemented in the future, but in the meantime, your only option is to use the Docker or Node deployment method.

How it Works#

When the app is loaded, if appConfig.statusCheck: true is set, or if any items have the statusCheck: true enabled, then Dashy will make a request, to https://[your-host-name]/status-check?url=[address-or-servce] (may al include GET params for headers and the secure flag), which in turn will ping that running service, and respond with a status code. Response time is calculated from the difference between start and end time of the request.

When the response completes, an indicator will display next to each item. The color denotes the status: Yellow while waiting for the response to return, green if request was successful, red if it failed, and grey if it was unable to make the request all together.

All requests are made straight from your server, there is no intermediary. So providing you are hosting Dashy yourself, and are checking the status of other self-hosted services, there shouldn't be any privacy concerns. Requests are made asynchronously, so this won't have any significant impact on page load speeds. However recurring requests (using statusCheckInterval) may run more slowly if the interval between requests is very short.

- + \ No newline at end of file diff --git a/docs/theming/index.html b/docs/theming/index.html index 4a4dbd92..331441e7 100644 --- a/docs/theming/index.html +++ b/docs/theming/index.html @@ -6,14 +6,14 @@ Theming | Dashy - +

Theming

By default Dashy comes with 25+ built-in themes, which can be applied from the dropdown menu in the UI.

Built-in Themes

You can also add your own themes, apply custom styles, and modify colors.

You can customize Dashy by writing your own CSS, which can be loaded either as an external stylesheet, set directly through the UI, or specified in the config file. Most styling options can be set through CSS variables, which are outlined below.

The following content requires that you have a basic understanding of CSS. If you're just beginning, you may find this article helpful.

How Theme-Switching Works#

The theme switching is done by simply changing the data-theme attribute on the root DOM element, which can then be targeted by CSS. First off, in order for the theme to show up in the theme switcher, it needs to be added to the config file, under appConfig.cssThemes, either as a string, or an array of strings for multiple themes. For example:

appConfig:  cssThemes: ['tiger', 'another-theme']

You can now create a block to target you're theme with html[data-theme='my-theme']{} and set some styles. The easiest method is by setting CSS variables, but you can also directly override elements by their selector. As an example, see the built-in CSS themes.

html[data-theme='tiger'] {  --primary: #f58233;  --background: #0b1021;}

Finally, from the UI use the theme dropdown menu to select your new theme, and your styles will be applied.

You can also set appConfig.theme to pre-select a default theme, which will be applied immediately after deployment.

Modifying Theme Colors#

Themes can be modified either through the UI, using the color picker menu (to the right of the theme dropdown), or directly in the config file, under appConfig.customColors. Here you can specify the value for any of the available CSS variables.

Example Themes

By default, any color modifications made to the current theme through the UI will only be applied locally. If you need these settings to be set globally, then click the 'Export' button, to get the color codes and variable names, which can then be backed up, or saved in your config file.

Custom colors are saved relative the the base theme selected. So if you switch themes after setting custom colors, then you're settings will no longer be applied. You're changes are not lost though, and switching back to the original theme will see your styles reapplied.

If these values are specified in your conf.yml file, then it will look something like the below example. Note that in YAML, values or keys which contain special characters, must be wrapped in quotes.

appConfig:  customColors:    oblivion:      primary: '#75efff'      background: '#2a3647'    dracula:      primary: '#8be9fd'

Adding your own Theme#

User-defined styles and custom themes should be defined in ./src/styles/user-defined-themes.scss. If you're using Docker, you can pass your own stylesheet in using the --volume flag. E.g. v ./my-themes.scss:/app/src/styles/user-defined-themes.scss. Don't forget to pass your theme name into appConfig.cssThemes so that it shows up on the theme-switcher dropdown.

Setting Custom CSS in the UI#

Custom CSS can be developed, tested and applied directly through the UI. Although you will need to make note of your changes to apply them across instances.

This can be done from the Config menu (spanner icon in the top-right), under the Custom Styles tab. This is then associated with appConfig.customCss in local storage. Styles can also be directly applied to this attribute in the config file, but this may get messy very quickly if you have a lot of CSS.

Page-Specific Styles#

If you've got multiple pages within your dashboard, you can choose to target certain styles to specific pages. The top-most element within <body> will have a class name specific to the current sub-page. This is usually the page's name, all lowercase, with dashes instead of spaces, but you can easily check this yourself within the dev tools.

For example, if the pages name was "CFT Toolbox", and you wanted to target .items, you would do:

.cft-toolbox .item { border: 4px solid yellow; }

Loading External Stylesheets#

The URI of a stylesheet, either local or hosted on a remote CDN can be passed into the config file. The attribute appConfig.externalStyleSheet accepts either a string, or an array of strings. You can also pass custom font stylesheets here, they must be in a CSS format (for example, https://fonts.googleapis.com/css2?family=Cutive+Mono). This is handled in ThemeHelper.js.

For example:

appConfig:  externalStyleSheet: 'https://example.com/my-stylesheet.css'
appConfig:  externalStyleSheet: ['/themes/my-theme-1.css', '/themes/my-theme-2.css']

Hard-Coding Section or Item Colors#

Some UI components have a color option, that can be set in the config file, to force the color of a given item or section no matter what theme is selected. These colors should be expressed as hex codes (e.g. #fff) or HTML colors (e.g. red). The following attributes are supported:

  • section.color - Custom color for a given section
  • item.color - Font and icon color for a given item
  • item.backgroundColor - Background color for a given icon

Typography#

Essential fonts bundled within the app are located within ./src/assets/fonts/. All optional fonts that are used by themes are stored in ./public/fonts/, if you want to add your own font, this is where you should put it. As with assets, if you're using Docker then using a volume to link a directory on your host system with this path within the container will make management much easier.

Fonts which are not being used by the current theme are not fetched on page load. They are instead only loaded into the application if and when they are required. So having multiple themes with various typefaces shouldn't have any negative impact on performance.

Full credit to the typographers behind each of the included fonts. Specifically: Matt McInerney, Christian Robertson, Haley Fiege, Peter Hull, Cyreal and the legendary Vernon Adams

CSS Variables#

All colors as well as other variable values (such as borders, border-radius, shadows) are specified as CSS variables. This makes theming the application easy, as you only need to change a given color or value in one place. You can find all variables in color-palette.scss and the themes which make use of these color variables are specified in color-themes.scss

CSS variables are simple to use. You define them like: --background: #fff; and use them like: body { background-color: var(--background); }. For more information, see this guide on using CSS Variables.

You can determine the variable used by any given element, and visualize changes using the browser developer tools (Usually opened with F12, or Options --> More --> Developer Tools). Under the elements tab, click the Element Selector icon (usually top-left corner), you will then be able to select any DOM element on the page by hovering and clicking it. In the CSS panel you will see all styles assigned to that given element, including CSS variables. Click a variable to see it's parent value, and for color attributes, click the color square to modify the color. For more information, see this getting started guide, and these articles on selecting elements and inspecting and modifying colors.

Top-Level Variables#

These are all that are required to create a theme. All other variables inherit their values from these variables, and can optionally be overridden.

  • --primary - Application primary color. Used for title, text, accents, and other features
  • --background - Application background color
  • --background-darker - Secondary background color (usually darker), used for navigation bar, section fill, footer etc
  • --curve-factor - The border radius used globally throughout the application. Specified in px, defaults to 5px
  • --dimming-factor - Inactive elements have slight transparency. This can be between 0 (invisible) and 1 (normal), defaults to 0.7

Targeted Color Variables#

You can target specific elements on the UI with these variables. All are optional, since by default, they inherit their values from above

  • --heading-text-color - Text color for web page heading and sub-heading. Defaults to --primary
  • --nav-link-text-color - The text color for links displayed in the navigation bar. Defaults to --primary
  • --nav-link-background-color - The background color for links displayed in the navigation bar
  • --nav-link-text-color-hover - The text color when a navigation bar link is hovered over. Defaults to --primary
  • --nav-link-background-color-hover - The background color for nav bar links when hovered over
  • --nav-link-border-color - The border color for nav bar links. Defaults to transparent
  • --nav-link-border-color-hover - The border color for nav bar links when hovered over. Defaults to --primary
  • --search-container-background - Background for the container containing the search bar. Defaults to --background-darker
  • --search-field-background - Fill color for the search bar. Defaults to --background
  • --settings-background - The background for the quick settings. Defaults to --background
  • --settings-text-color - The text and icon color for quick settings. Defaults to --primary
  • --footer-text-color - Color for text within the footer. Defaults to --medium-grey
  • --footer-text-color-link - Color for any hyperlinks within the footer. Defaults to --primary
  • --item-text-color - The text and icon color for items. Defaults to --primary
  • --item-group-outer-background - The background color for the outer part of a section (including section head). Defaults to --primary
  • --item-group-background - The background color for the inner part of item groups. Defaults to #0b1021cc (semi-transparent black)
  • --item-group-heading-text-color - The text color for section headings. Defaults to --item-group-background;
  • --item-group-heading-text-color-hover - The text color for section headings, when hovered. Defaults to --background
  • --config-code-background - Background color for the JSON editor in the config menu. Defaults to #fff (white)
  • --config-code-color - Text color for the non-highlighted code within the JSON editor. Defaults to --background
  • --config-settings-color - The background for the config/ settings pop-up modal. Defaults to --primary
  • --config-settings-background - The text color for text within the settings container. Defaults to --background-darker
  • --scroll-bar-color - Color of the scroll bar thumb. Defaults to --primary
  • --scroll-bar-background Color of the scroll bar blank space. Defaults to --background-darker
  • --highlight-background Fill color for text highlighting. Defaults to --primary
  • --highlight-color Text color for selected/ highlighted text. Defaults to --background
  • --toast-background - Background color for the toast info popup. Defaults to --primary
  • --toast-color - Text, icon and border color in the toast info popup. Defaults to --background
  • --welcome-popup-background - Background for the info pop-up shown on first load. Defaults to --background-darker
  • --welcome-popup-text-color - Text color for the welcome pop-up. Defaults to --primary
  • --side-bar-background - Background color of the sidebar used in the workspace view. Defaults to --background-darker
  • --side-bar-color - Color of icons and text within the sidebar. Defaults to --primary
  • --status-check-tooltip-background - Background color for status check tooltips. Defaults to --background-darker
  • --status-check-tooltip-color - Text color for the status check tooltips. Defaults to --primary
  • --code-editor-color - Text color used within raw code editors. Defaults to --black
  • --code-editor-background - Background color for raw code editors. Defaults to --white
  • --context-menu-color - Text color for right-click context menu over items. Defaults to --primary
  • --context-menu-background - Background color of right-click context menu. Defaults to --background
  • --context-menu-secondary-color - Border and outline color for context menu. Defaults to --background-darker

Non-Color Variables#

  • --outline-color - Used to outline focused or selected elements
  • --curve-factor-navbar - The border radius of the navbar. Usually this is greater than --curve-factor
  • --scroll-bar-width - Width of horizontal and vertical scroll bars. E.g. 8px
  • --item-group-padding - Inner padding of sections, determines the width of outline. E.g. 5px
  • --item-shadow - Shadow for items. E.g. 1px 1px 2px #130f23
  • --item-hover-shadow - Shadow for items when hovered over. E.g. 1px 2px 4px #373737
  • --item-icon-transform - A transform property, to modify item icons. E.g. drop-shadow(2px 4px 6px var(--transparent-50)) saturate(0.65)
  • --item-icon-transform-hover - Same as above, but applied when an item is hovered over. E.g. drop-shadow(4px 8px 3px var(--transparent-50)) saturate(2)
  • --item-group-shadow - The shadow for an item group/ section. Defaults to --item-shadow
  • --settings-container-shadow - A shadow property for the settings container. E.g. none

Action Colors#

These colors represent intent, and so are not often changed, but you can do so if you wish

  • --info - Information color, usually blue / #04e4f4
  • --success - Success color, usually green / #20e253
  • --warning - Warning color, usually yellow / #f6f000
  • --danger - Error/ danger color, usually red / #f80363
  • --neutral - Neutral color, usually grey / #272f4d
  • --white - Just white / #fff
  • --black - Just black / #000
- + \ No newline at end of file diff --git a/docs/troubleshooting/index.html b/docs/troubleshooting/index.html index 6c5fa277..5499609c 100644 --- a/docs/troubleshooting/index.html +++ b/docs/troubleshooting/index.html @@ -6,7 +6,7 @@ Troubleshooting | Dashy - + @@ -34,7 +34,7 @@ This will not affect your config file. But be sure that you keep a backup of you Then describe the issue, briefly explaining the steps to reproduce, expected outcome and actual outcome.

Step 4 - Provide Supporting Info#

Where relevant please also include:

  • A screenshot of the issue
  • The relevant parts of your config file
  • Logs
    • If client-side issue, then include the browser logs (see how)
    • If server-side / during deployment, include the terminal output

Take care to redact any personal info, (like IP addresses, auth hashes or API keys).

Step 5 - Fix Released#

A maintainer will aim to respond within 48 hours. The timeframe for resolving your issue, will vary depending on severity of the bug and the complexity of the fix. You will be notified on your ticket, when a fix has been released.

Finally, be sure to remain respectful to other users and project maintainers, in line with the Contributor Covenant Code of Conduct.


How-To Open Browser Console#

When raising a bug, one crucial piece of info needed is the browser's console output. This will help the developer diagnose and fix the issue.

If you've been asked for this info, but are unsure where to find it, then it is under the "Console" tab, in the browsers developer tools, which can be opened with F12. You can right-click the console, and select Save As to download the log.

To open dev tools, and jump straight to the console:

  • Win / Linux: Ctrl + Shift + J
  • MacOS: Cmd + Option + J

For more detailed walk through, see this article.


Git Contributions not Displaying#

If you've contributed to Dashy (or any other project), but your contributions are not showing up on your GH profile, or in Dashy's Credits Page, then this is likely a git config issue.

These statistics are generated using the username / email associated with commits. This info needs to be setup on your local machine using git config.

Run the following commands (replacing name + email with your info):

  • git config --global user.name "John Doe"
  • git config --global user.email johndoe@example.com

For more info, see Git First Time Setup Docs.

Note that only contributions to the master / main branch or a project are counted

- + \ No newline at end of file diff --git a/docs/widgets/index.html b/docs/widgets/index.html index f2685013..22560278 100644 --- a/docs/widgets/index.html +++ b/docs/widgets/index.html @@ -6,23 +6,23 @@ Widgets | Dashy - +
-

Widgets

Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API.

Contents#

General Widgets#

Clock#

A simple, live-updating time and date widget with time-zone support. All fields are optional.

Options#

FieldTypeRequiredDescription
timeZonestringOptionalThe time zone to display date and time in.
Specified as Region/City, for example: Australia/Melbourne. See the Time Zone DB for a full list of supported TZs. Defaults to the browser / device's local time
formatstringOptionalA country code for displaying the date and time in local format.
Specified as [ISO-3166]-[ISO-639], for example: en-AU. See here for a full list of locales. Defaults to the browser / device's region
customCityNamestringOptionalBy default the city from the time-zone is shown, but setting this value will override that text
hideDatebooleanOptionalIf set to true, the date and city will not be shown. Defaults to false
hideSecondsbooleanOptionalIf set to true, seconds will not be shown. Defaults to false
use12HourbooleanOptionalIf set to true, 12 hour time will be displayed. Defaults to the settings suggested by the current format and timeZone

Example#

- type: clock  options:    timeZone: Europe/London    format: en-GB    hideDate: false

Info#

No external data requests.


Weather#

A simple, live-updating local weather component, showing temperature, conditions and more info.

Options#

FieldTypeRequiredDescription
apiKeystringRequiredYour OpenWeatherMap API key. You can get one for free at openweathermap.org
citystringRequiredA city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format
unitsstringOptionalThe units to use for displaying data, can be either metric or imperial. Defaults to metric
hideDetailsbooleanOptionalIf set to true, the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to false
latnumberOptionalTo show weather for a specific location, you can provide the latitude and longitude coordinates. If provided, this will override the city option
lonnumberOptionalTo show weather for a specific location, you can provide the latitude and longitude coordinates. If provided, this will override the city option

Example#

- type: weather  options:    apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    city: London    units: metric    hideDetails: true

Info#


Weather Forecast#

Displays the weather (temperature and conditions) for the next few days for a given location. Note that this requires either the free OpenWeatherMap Student Plan, or the Premium Plan.

Options#

FieldTypeRequiredDescription
apiKeystringRequiredYour OpenWeatherMap API key. You can get one at openweathermap.org or for free via the OWM Student Plan
citystringRequiredA city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format
numDaysnumberOptionalThe number of days to display of forecast info to display. Defaults to 4, max 16 days
unitsstringOptionalThe units to use for displaying data, can be either metric or imperial. Defaults to metric
hideDetailsbooleanOptionalIf set to true, the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to false

Example#

- type: weather-forecast  options:    city: California    numDays: 6    apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    units: imperial

Info#

  • CORS: 🟢 Enabled
  • Auth: 🔴 Required
  • Price: 🔴 Premium (free for personal use only)
  • Privacy: See OWM Privacy Policy

RSS Feed#

Display news and updates from any RSS-enabled service.

Options#

FieldTypeRequiredDescription
rssUrlstringRequiredThe URL location of your RSS feed
apiKeystringOptionalAn API key for rss2json. It's free, and will allow you to make 10,000 requests per day, you can sign up here
limitnumberOptionalThe number of posts to return. If you haven't specified an API key, this will be limited to 10
orderBystringOptionalHow results should be sorted. Can be either pubDate, author or title. Defaults to pubDate
orderDirectionstringOptionalOrder direction of feed items to return. Can be either asc or desc. Defaults to desc
parseLocallybooleanOptionalIf true parse the rss feed locally instead of using the rss2json API.

Example#

- type: rss-feed  options:    rssUrl: https://www.schneier.com/blog/atom.xml    apiKey: xxxx

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟠 Optional
  • Price: 🟠 Free Plan (up to 10,000 requests / day)
  • Privacy: See Rss2Json Privacy Policy

Image#

Displays an image.

This may be useful if you have a service (such as Grafana - see example), which periodically exports charts or other data as an image.

You can also store images within Dashy's public directory (using a Docker volume), and reference them directly. E.g. -v ./path/to/my-homelab-logo.png:/app/public/logo.png, then in the widget imagePath: /logo.png.

Similarly, any web service that serves up widgets as image can be used. E.g. you could show current star chart for a GitHub repo, with: imagePath: https://starchart.cc/Lissy93/dashy.svg.

If you'd like to embed a live screenshot, of all or just part of a website, then this can be done using API Flash.

Or what about showing a photo of the day? Try https://source.unsplash.com/random/400x300 or https://picsum.photos/400/300

Options#

FieldTypeRequiredDescription
imagePathstringRequiredThe path (local or remote) of the image to display
imageWidthstringOptionalSpecify a fixed width for rendered image. Accepts either integer value in px, or any string value with units (e.g. 420, 100px, 6.9rem) (defaults to auto)
imageHeightstringOptionalSpecify a fixed height for rendered image. Accepts either integer value in px, or any string value with units (e.g. 420, 100px, 6.9rem) (defaults to auto)

Example#

- type: image  options:    imagePath: https://i.ibb.co/yhbt6CY/dashy.png

Info#

Unless image fetched from remote source, no external data request is made.


Public IP#

Often find yourself searching "What's my IP", just so you can check your VPN is still connected? This widget displays your public IP address, along with ISP name and approx location. Data can be fetched from either IpApi.co, IP-API.com or IpGeolocation.io.

Options#

All fields are optional.

FieldTypeRequiredDescription
providerstringOptionalThe name of the service to fetch IP address from. Can be either ipapi.co, ip-api or ipgeolocation. Defaults to ipapi.co. Note, ip-api doesn't work on HTTPS, and if you set to ipgeolocation then you must also provide an API key
apiKeystringOptionalOnly required if provider is set to ipgeolocation. You can get a free API key here

Example#

- type: public-ip

Or

- type: public-ip  options:    provider: ipgeolocation    apiKey: xxxxxxxxxxxxxxx

Info#


IP Blacklist#

Notice certain web pages aren't loading? This widget quickly shows which blacklists your IP address (or host, or email) appears on, using data from blacklistchecker.com.

Options#

FieldTypeRequiredDescription
ipAddressstringOptionalThe IP to check. This can also be a domain/ host name or even an email address. If left blank, Dashy will use your current public IP address.
apiKeystringRequiredYou can get your free API key from blacklistchecker.com

Example#

- type: blacklist-check  options:    apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    ipAddress: 1.1.1.1

Info#


Domain Monitor#

Keep an eye on the expiry dates of your domain names, using public whois records fetched from whoapi.com. Click the domain name to view additional info, like registrar, name servers and date last updated.

Options#

FieldTypeRequiredDescription
domainstringRequiredThe domain to check
apiKeystringRequiredYou can get your free API key from my.whoapi.com
showFullInfobooleanOptionalIf set to true, the toggle-full-info panel will be open by default

Example#

  - type: domain-monitor    options:      domain: example.com      apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+

Widgets

Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API.

Contents#

General Widgets#

Clock#

A simple, live-updating time and date widget with time-zone support. All fields are optional.

Options#

FieldTypeRequiredDescription
timeZonestringOptionalThe time zone to display date and time in.
Specified as Region/City, for example: Australia/Melbourne. See the Time Zone DB for a full list of supported TZs. Defaults to the browser / device's local time
formatstringOptionalA country code for displaying the date and time in local format.
Specified as [ISO-3166]-[ISO-639], for example: en-AU. See here for a full list of locales. Defaults to the browser / device's region
customCityNamestringOptionalBy default the city from the time-zone is shown, but setting this value will override that text
hideDatebooleanOptionalIf set to true, the date and city will not be shown. Defaults to false
hideSecondsbooleanOptionalIf set to true, seconds will not be shown. Defaults to false
use12HourbooleanOptionalIf set to true, 12 hour time will be displayed. Defaults to the settings suggested by the current format and timeZone

Example#

- type: clock  options:    timeZone: Europe/London    format: en-GB    hideDate: false

Info#

No external data requests.


Weather#

A simple, live-updating local weather component, showing temperature, conditions and more info.

Options#

FieldTypeRequiredDescription
apiKeystringRequiredYour OpenWeatherMap API key. You can get one for free at openweathermap.org
citystringRequiredA city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format
unitsstringOptionalThe units to use for displaying data, can be either metric or imperial. Defaults to metric
hideDetailsbooleanOptionalIf set to true, the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to false
latnumberOptionalTo show weather for a specific location, you can provide the latitude and longitude coordinates. If provided, this will override the city option
lonnumberOptionalTo show weather for a specific location, you can provide the latitude and longitude coordinates. If provided, this will override the city option

Example#

- type: weather  options:    apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    city: London    units: metric    hideDetails: true

Info#


Weather Forecast#

Displays the weather (temperature and conditions) for the next few days for a given location. Note that this requires either the free OpenWeatherMap Student Plan, or the Premium Plan.

Options#

FieldTypeRequiredDescription
apiKeystringRequiredYour OpenWeatherMap API key. You can get one at openweathermap.org or for free via the OWM Student Plan
citystringRequiredA city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format
numDaysnumberOptionalThe number of days to display of forecast info to display. Defaults to 4, max 16 days
unitsstringOptionalThe units to use for displaying data, can be either metric or imperial. Defaults to metric
hideDetailsbooleanOptionalIf set to true, the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to false

Example#

- type: weather-forecast  options:    city: California    numDays: 6    apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    units: imperial

Info#

  • CORS: 🟢 Enabled
  • Auth: 🔴 Required
  • Price: 🔴 Premium (free for personal use only)
  • Privacy: See OWM Privacy Policy

RSS Feed#

Display news and updates from any RSS-enabled service.

Options#

FieldTypeRequiredDescription
rssUrlstringRequiredThe URL location of your RSS feed
apiKeystringOptionalAn API key for rss2json. It's free, and will allow you to make 10,000 requests per day, you can sign up here
limitnumberOptionalThe number of posts to return. If you haven't specified an API key, this will be limited to 10
orderBystringOptionalHow results should be sorted. Can be either pubDate, author or title. Defaults to pubDate
orderDirectionstringOptionalOrder direction of feed items to return. Can be either asc or desc. Defaults to desc
parseLocallybooleanOptionalIf true parse the rss feed locally instead of using the rss2json API.

Example#

- type: rss-feed  options:    rssUrl: https://www.schneier.com/blog/atom.xml    apiKey: xxxx

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟠 Optional
  • Price: 🟠 Free Plan (up to 10,000 requests / day)
  • Privacy: See Rss2Json Privacy Policy

Image#

Displays an image.

This may be useful if you have a service (such as Grafana - see example), which periodically exports charts or other data as an image.

You can also store images within Dashy's public directory (using a Docker volume), and reference them directly. E.g. -v ./path/to/my-homelab-logo.png:/app/public/logo.png, then in the widget imagePath: /logo.png.

Similarly, any web service that serves up widgets as image can be used. E.g. you could show current star chart for a GitHub repo, with: imagePath: https://starchart.cc/Lissy93/dashy.svg.

If you'd like to embed a live screenshot, of all or just part of a website, then this can be done using API Flash.

Or what about showing a photo of the day? Try https://source.unsplash.com/random/400x300 or https://picsum.photos/400/300

Options#

FieldTypeRequiredDescription
imagePathstringRequiredThe path (local or remote) of the image to display
imageWidthstringOptionalSpecify a fixed width for rendered image. Accepts either integer value in px, or any string value with units (e.g. 420, 100px, 6.9rem) (defaults to auto)
imageHeightstringOptionalSpecify a fixed height for rendered image. Accepts either integer value in px, or any string value with units (e.g. 420, 100px, 6.9rem) (defaults to auto)

Example#

- type: image  options:    imagePath: https://i.ibb.co/yhbt6CY/dashy.png

Info#

Unless image fetched from remote source, no external data request is made.


Public IP#

Often find yourself searching "What's my IP", just so you can check your VPN is still connected? This widget displays your public IP address, along with ISP name and approx location. Data can be fetched from either IpApi.co, IP-API.com or IpGeolocation.io.

Options#

All fields are optional.

FieldTypeRequiredDescription
providerstringOptionalThe name of the service to fetch IP address from. Can be either ipapi.co, ip-api or ipgeolocation. Defaults to ipapi.co. Note, ip-api doesn't work on HTTPS, and if you set to ipgeolocation then you must also provide an API key
apiKeystringOptionalOnly required if provider is set to ipgeolocation. You can get a free API key here

Example#

- type: public-ip

Or

- type: public-ip  options:    provider: ipgeolocation    apiKey: xxxxxxxxxxxxxxx

Info#


IP Blacklist#

Notice certain web pages aren't loading? This widget quickly shows which blacklists your IP address (or host, or email) appears on, using data from blacklistchecker.com.

Options#

FieldTypeRequiredDescription
ipAddressstringOptionalThe IP to check. This can also be a domain/ host name or even an email address. If left blank, Dashy will use your current public IP address.
apiKeystringRequiredYou can get your free API key from blacklistchecker.com

Example#

- type: blacklist-check  options:    apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    ipAddress: 1.1.1.1

Info#


Domain Monitor#

Keep an eye on the expiry dates of your domain names, using public whois records fetched from whoapi.com. Click the domain name to view additional info, like registrar, name servers and date last updated.

Options#

FieldTypeRequiredDescription
domainstringRequiredThe domain to check
apiKeystringRequiredYou can get your free API key from my.whoapi.com
showFullInfobooleanOptionalIf set to true, the toggle-full-info panel will be open by default

Example#

  - type: domain-monitor    options:      domain: example.com      apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   - type: domain-monitor    options:      domain: example2.com      apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Info#

  • CORS: 🟢 Enabled
  • Auth: 🔴 Required
  • Price: 🟠 Free Plan (10,000 requests)
  • Host: Managed Instance Only
  • Privacy: See WhoAPI Privacy Policy

Crypto Watch List#

Keep track of price changes of your favorite crypto assets. Data is fetched from CoinGecko. All fields are optional.

Options#

FieldTypeRequiredDescription
assetsstringOptionalAn array of cryptocurrencies, coins and tokens. See list of supported assets. If none are specified, then the top coins by sortBy (defaults to market cap) will be returned
currencystringOptionalThe fiat currency to display price in, expressed as an ISO-4217 alpha code (see list of currencies). Defaults to USD
sortBystringOptionalThe method of sorting results. Can be marketCap, volume or alphabetical. Defaults to marketCap.
limitnumberOptionalNumber of results to return, useful when no assets are specified. Defaults to either all or 100

Example#

- type: crypto-watch-list  options:    limit: 10

Or

  - type: crypto-watch-list    options:      currency: GBP      sortBy: marketCap      assets:      - bitcoin      - ethereum      - monero      - cosmos      - polkadot      - dogecoin

Info#


Crypto Token Price History#

Shows recent price history for a given crypto asset, using price data fetched from CoinGecko

Options#

FieldTypeRequiredDescription
assetstringRequiredName of a crypto asset, coin or token to fetch price data for, see list of supported assets
currencystringOptionalThe fiat currency to display results in, expressed as an ISO-4217 alpha code (see list of currencies). Defaults to USD
numDaysnumberOptionalThe number of days of price history to render. Defaults to 7, min: 1, max: 30 days
chartColorstringOptionalColor of the chart value. Defaults to --widget-text-color which inherits dashboard primary color
chartHeightnumberOptionalThe height of rendered chart in px. Defaults to 300

Example#

- type: crypto-price-chart  options:    asset: bitcoin    currency: GBP    numDays: 7

Info#


Wallet Balance#

Keep track of your crypto balances and see recent transactions. Data is fetched from BlockCypher

Options#

FieldTypeRequiredDescription
coinstringRequiredSymbol of coin or asset, e.g. btc, eth or doge
addressstringRequiredAddress to monitor. This is your wallet's public / receiving address
networkstringOptionalTo use a different network, other than mainnet. Defaults to main
limitnumberOptionalLimit the number of transactions to display. Defaults to 10, set to large number to show all

Example#

- type: wallet-balance  options:    coin: btc    address: 3853bSxupMjvxEYfwGDGAaLZhTKxB2vEVC

Info#


Code Stats#

Display your coding summary. Code::Stats is a free and open source app that aggregates statistics about your programming activity. Dashy supports both the public instance, as well as self-hosted versions.

Options#

FieldTypeRequiredDescription
usernamestringRequiredYour CodeStats username
hostnamestringOptionalIf your self-hosting CodeStats, then supply the host name. By default it will use the public hosted instance
monthsToShownumberOptionalSpecify the number of months to render in the historical data chart. Defaults to 6
hideMetabooleanOptionalOptionally hide the meta section (username, level, all-time and recent XP)
hideHistorybooleanOptionalOptionally hide the historical calendar heat map
hideLanguagesbooleanOptionalOptionally hide the programming languages pie chart
hideMachinesbooleanOptionalOptionally hide the machines percentage chart

Example#

- type: code-stats  options:    username: alicia

Info#


Mullvad Status#

Shows your Mullvad VPN connection status, as well as server info. Fetched from am.i.mullvad.net

Options#

No Options.

Example#

- type: mullvad-status

Info#


AnonAddy#

AnonAddy is a free and open source mail forwarding service. Use it to protect your real email address, by using a different alias for each of your online accounts, and have all emails land in your normal inbox(es). Supports custom domains, email replies, PGP-encryption, multiple recipients and more

This widget display email addresses / aliases from AnonAddy. Click an email address to copy to clipboard, or use the toggle switch to enable/ disable it. Shows usage stats (bandwidth, used aliases etc), as well as total messages received, blocked and sent. Works with both self-hosted and managed instances of AnonAddy.

Options#

FieldTypeRequiredDescription
apiKeystringRequiredYour AnonAddy API Key / Personal Access Token. You can generate this under Account Settings
hostnamestringOptionalIf your self-hosting AnonAddy, then supply the host name. By default it will use the public hosted instance
apiVersionstringOptionalIf you're using an API version that is not version v1, then specify it here
limitnumberOptionalLimit the number of emails shown per page. Defaults to 10
sortBystringOptionalSpecify the sort order for email addresses. Defaults to updated_at. Can be either: local_part, domain, email, emails_forwarded, emails_blocked, emails_replied, emails_sent, created_at, updated_at or deleted_at. Precede with a - character to reverse order.
searchTermstringOptionalA search term to filter results by, will search the email, description and domain
disableControlsbooleanOptionalPrevent any changes being made to account through the widget. User will not be able to enable or disable aliases through UI when this option is set
hideMetabooleanOptionalDon't show account meta info (forward/ block count, quota usage etc)
hideAliasesbooleanOptionalDon't show email address / alias list. Will only show account meta info

Example#

  - type: anonaddy    options:      apiKey: "xxxxxxxxxxxxxxxxxxxxxxxx\        xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\        xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"      limit: 5      sortBy: created_at      disableControls: true

Info#

  • CORS: 🟢 Enabled
  • Auth: 🔴 Required
  • Price: 🟠 Free for Self-Hosted / Free Plan available on managed instance or $1/month for premium
  • Host: Self-Hosted or Managed
  • Privacy: See AnonAddy Privacy Policy

Vulnerability Feed#

Keep track of recent security advisories and vulnerabilities, with optional filtering by score, exploits, vendor and product. All fields are optional.

Options#

FieldTypeRequiredDescription
sortBystringOptionalThe sorting method. Can be either publish-date, last-update or cve-code. Defaults to publish-date
limitnumberOptionalThe number of results to fetch. Can be between 5 and 30, defaults to 10
minScorenumberOptionalIf set, will only display results with a CVE score higher than the number specified. Can be a number between 0 and 9.9. By default, vulnerabilities of all CVE scores are shown
hasExploitbooleanOptionalIf set to true, will only show results with active exploits. Defaults to false
vendorIdnumberOptionalOnly show results from a specific vendor, specified by ID. See Vendor Search for list of vendors. E.g. 23 (Debian), 26 (Microsoft), 23682 (CloudFlare)
productIdnumberOptionalOnly show results from a specific app or product, specified by ID. See Product Search for list of products. E.g. 28125 (Docker), 34622 (NextCloud), 50211 (Portainer), 95391 (ProtonMail)

Example#

- type: cve-vulnerabilities

or

- type: cve-vulnerabilities  options:    sortBy: publish-date    productId: 28125    hasExploit: false    minScore: 5    limit: 30

Info#


Exchange Rates#

Display current FX rates in your native currency. Hover over a row to view more info, or click to show rates in that currency.

Options#

FieldTypeRequiredDescription
inputCurrencystringRequiredThe base currency to show results in. Specified as a 3-letter ISO-4217 code, see here for the full list of supported currencies, and their symbols
outputCurrenciesarrayRequiredList or currencies to show results for. Specified as a 3-letter ISO-4217 code, see here for the full list of supported currencies, and their symbols
apiKeystringRequiredAPI key for exchangerate-api.com, usually a 24-digit alpha-numeric string. You can sign up for a free account here

Example#

- type: exchange-rates  options:    apiKey: xxxxxxxxxxxxxxxxxxxxxxxx    inputCurrency: GBP    outputCurrencies:      - USD      - JPY      - HKD      - KPW

Info#

  • CORS: 🟢 Enabled
  • Auth: 🔴 Required
  • Price: 🟠 Free plan (up to 100,000 requests/ month)
  • Host: Managed Instance Only
  • Privacy: See ExchangeRateAPI Privacy Policy

Public Holidays#

Counting down to the next day off work? This widget displays upcoming public holidays for your country. Data is fetched from Enrico

Note, config for this widget is case-sensetive (see #1268)

Options#

FieldTypeRequiredDescription
countrystringRequiredThe country to fetch holiday data for, specified as a country code, e.g. GB or US
statestringOptionalrestrict a country to a specific state defined by ISO_3166-2, e.g. LND.
holidayTypestringOptionalThe type of holidays to fetch. Can be: all, public_holiday, observance, school_holiday, other_day or extra_working_day. Defaults to public_holiday
monthsToShownumberOptionalThe number of months in advance to show. Min: 1, max: 24. Defaults to 12
langstringOptionalThe language in which the events should be. Usually local languages and english are available. Default to first available in the country. e.g. en or fr.

Example#

- type: public-holidays  options:    country: GB    region: LND    holidayType: all    monthsToShow: 12    lang: en

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Not Required
  • Price: 🟢 Free
  • Host: Self-Hosted (see jurajmajer/enrico) or Managed
  • Privacy: ⚫ No Policy Available

Covid-19 Status#

Keep track of the current COVID-19 status. Optionally also show cases by country, and a time-series chart. Uses live data from various sources, computed by disease.sh

Options#

FieldTypeRequiredDescription
showChartbooleanOptionalAlso display a time-series chart showing number of recent cases
showCountriesbooleanOptionalAlso display a list of cases per country
numDaysnumberOptionalSpecify number of days worth of history to render on the chart
countriesstring[]OptionalAn array of countries to display, specified by their ISO-3 codes. Leave blank to show all, sorted by most cases. showCountries must be set to true
limitnumberOptionalIf showing all countries, set a limit for number of results to return. Defaults to 10, no maximum

Example#

- type: covid-stats

Or

- type: covid-stats  options:    showChart: true    showCountries: true    countries:    - GBR    - USA    - IND    - RUS

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Not Required
  • Price: 🟢 Free
  • Host: Managed Instance or Self-Hosted (see disease-sh/api)
  • Privacy: ⚫ No Policy Available
  • Conditions: Terms of Use

Sports Scores#

Show recent scores and upcoming matches from your favourite sports team. Data is fetched from TheSportsDB.com. From the UI, you can click any other team to view their scores and upcoming games, or click a league name to see all teams.

Options#

FieldTypeRequiredDescription
teamIdstringOptionalThe ID of a team to fetch scores from. You can search for your team on the Teams Page
leagueIdstringOptionalAlternatively, provide a league ID to fetch all games from. You can find the ID on the Leagues Page
pastOrFuturestringOptionalSet to past to show scores for recent games, or future to show upcoming games. Defaults to past. You can change this within the UI
apiKeystringOptionalOptionally specify your API key, which you can sign up for at TheSportsDB.com
limitnumberOptionalTo limit output to a certain number of matches, defaults to 15
hideImagebooleanOptionalSet to true to not render the team / match banner image, defaults to false

Example#

- type: sports-scores  options:    teamId: 133636

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟠 Optional
  • Price: 🟠 Free plan (up to 30 requests / minute, limited endpoints)
  • Host: Managed Instance Only
  • Privacy: ⚫ No Policy Available

News Headlines#

Displays the latest news, click to read full article. Date is fetched from various news sources using Currents API

Options#

FieldTypeRequiredDescription
apiKeystringRequiredYour API key for CurrentsAPI. This is free, and you can get one here
countrystringOptionalFetch news only from a certain country or region. Specified as a country code, e.g. GB or US. See here for a list of supported regions
categorystringOptionalOnly return news from within a given category, e.g. sports, programming, world, science. The following categories are supported
langstringOptionalSpecify the language for returned articles as a 2-digit ISO code (limited article support). The following languages are supported, defaults to en
countnumberOptionalLimit the number of results. Can be between 1 and 200, defaults to 10
keywordsstringOptionalOnly return articles that contain an exact match within their title or description
hideImagesbooleanOptionalIf set to true, then article image thumbnails will not be displayed

Example#

- type: news-headlines    options:      apiKey: xxxxxxx      category: world

Info#

  • CORS: 🟢 Enabled
  • Auth: 🔴 Required
  • Price: 🟠 Free plan (up to 600 requests / day)
  • Host: Managed Instance Only
  • Privacy: See CurrentsAPI Privacy Policy

TFL Status#

Shows real-time tube status of the London Underground. All fields are optional.

Options#

FieldTypeRequiredDescription
showAllbooleanOptionalBy default, details for lines with a Good Service are not visible, but you can click More Details to see all. Setting this option to true will show all lines on initial page load
sortAlphabeticallybooleanOptionalBy default lines are sorted by current status, set this option to true to instead sort them alphabetically
linesToShowarrayOptionalBy default all lines are shown. If you're only interested in the status of a few lines, then pass in an array of lines to show, specified by name

Example#

- type: tfl-status
  - type: tfl-status    options:      showAll: true      sortAlphabetically: true      linesToShow:      - District      - Jubilee      - Central

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Not Required
  • Price: 🟢 Free
  • Host: Managed Instance Only
  • Privacy: See TFL Privacy Policy

Stock Price History#

Shows recent price history for a given publicly-traded stock or share

Options#

FieldTypeRequiredDescription
apiKeystringRequiredAPI key for Alpha Vantage, you can get a free API key here
stockstringRequiredThe stock symbol for the asset to fetch data for
priceTimestringOptionalThe time to fetch price for. Can be high, low, open or close. Defaults to high
chartColorstringOptionalColor of the chart value. Defaults to --widget-text-color which inherits dashboard primary color
chartHeightnumberOptionalThe height of rendered chart in px. Defaults to 300

Example#

- type: stock-price-chart  options:    stock: NET    apiKey: PGUWSWD6CZTXMT8N

Info#

  • CORS: 🟢 Enabled
  • Auth: 🔴 Required
  • Price: 🟠 Free plan (up to 500 requests/day)
  • Host: Managed Instance Only
  • Privacy: See AlphaVantage Privacy Policy

ETH Gas Prices#

Renders the current Gas cost of transactions on the Ethereum network (in both GWEI and USD), along with recent historical prices. Useful for spotting a good time to transact. Uses data from ethgas.watch

Options#

No config options.

Example#

- type: eth-gas-prices

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Not Required
  • Price: 🟢 Free
  • Host: Managed Instance or Self-Hosted (see wslyvh/ethgaswatch)
  • Privacy: ⚫ No Policy Available

Joke#

Renders a programming or generic joke. Data is fetched from the JokesAPI by @Sv443. All fields are optional.

Options#

FieldTypeRequiredDescription
categorystringOptionalSet the category of jokes to return. Use a string to specify a single category, or an array to pass in multiple options. Available options are: all, programming, pun, dark, spooky, christmas and misc. An up-to-date list of supported categories can be found here. Defaults to all
safeModebooleanOptionalSet to true, to prevent the fetching of any NSFW jokes. Defaults to false
languagestringOptionalSpecify the language for returned jokes. The following languages are supported: en, cs, de, es, fr and pt, and an up-to-date list of supported languages can be found here. By default, your system language will be used, if it's supported, otherwise English

Example#

- type: joke  options:    safeMode: true    language: en    category: Programming

Info#


XKCD Comics#

Have a laugh with the daily comic from XKCD. A classic webcomic website covering everything from Linux, math, romance, science and language. All fields are optional.

Options#

FieldTypeRequiredDescription
comicstring / numberOptionalChoose which comic to display. Set to either random, latest or the series number of a specific comic, like 627. Defaults to latest

Example#

- type: xkcd-comic  options:    comic: latest

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Not Required
  • Price: 🟢 Free
  • Privacy: ⚫ No Policy Available

Flight Data#

Displays airport departure and arrival flights, using data from AeroDataBox. Useful if you live near an airport and often wonder where the flight overhead is going to. Hover over a row for more flight data.

Options#

FieldTypeRequiredDescription
airportstringRequiredThe airport to show flight data from. Should be specified as a 4-character ICAO-code, a full list of which can be found here (example: KBJC or EGKK)
apiKeystringRequiredA valid RapidAPI Key, with AeroDataBox enabled (check in your Subscription Dashboard). This API is free to sign up for and use
limitnumberOptionalFor busy airports, you may wish to limit the number of results visible
directionstringOptionalBy default, both departure and arrival flights will be fetched, if you would like to only show flights in one direction, set this to wither departure or arrival

Example#

- type: flight-data  options:    airport: EGLC    apiKey: XXXXX    limit: 12    direction: all

Info#

  • CORS: 🟢 Enabled
  • Auth: 🔴 Required
  • Price: 🟠 Free plan (up to 150 requests / month)
  • Host: Managed Instance Only
  • Privacy: See AeroDataBox and RapidAPI Policy

Astronomy Picture of the Day#

Show the NASA Astronomy Picture of the Day. Data is fetched from APOD using @Lissy93/go-apod / hosted at apod.as93.net.

Options#

No config options.

Example#

- type: apod

Info#


GitHub Trending#

Displays currently trending projects on GitHub. Optionally specify a language and time-frame. Data is fetched from Lissy93/gh-trending-no-cors using the GitHub API. All fields are optional.

Options#

FieldTypeRequiredDescription
langstringOptionalA programming language to fetch trending repos from that category. E.g. javascript or go
sincestringOptionalThe timeframe to use when calculating trends. Can be either daily, weekly or monthly. Defaults to daily
limitnumberOptionalOptionally limit the number of results. Max 25, default is 10

Example#

- type: github-trending-repos  options:    limit: 8    since: weekly

Info#


GitHub Profile Stats#

Display stats from your GitHub profile, using embedded cards from anuraghazra/github-readme-stats

Options#

FieldTypeRequiredDescription
usernamestringRequiredThe GitHub username to fetch info for. E.g. lissy93. (Not required if hideProfileCard and hideLanguagesCard are both set to true)
hideProfileCardbooleanOptionalIf set to true, the users profile card will not be shown. Defaults to false
hideLanguagesCardbooleanOptionalIf set to true, the users top languages card will not be shown. Defaults to false
reposarrayOptionalIf you'd like to also display stats for some GitHub repositories, then add an array or repo names here. Specified as [username]/[repo-name], e.g. lissy93/dashy

Example#

- type: github-profile-stats  options:    username: Lissy93    hideLanguagesCard: true    repos:    - lissy93/dashy    - lissy93/personal-security-checklist    - lissy93/twitter-sentiment-visualisation

Info#


HealthChecks Status#

Display status of one or more HealthChecks project(s). Works with healthchecks.io and your selfhosted instance.

Options#

FieldTypeRequiredDescription
hoststringOptionalThe base url of your instance, default is https://healthchecks.io
apiKeystring or arrayRequiredOne or more API keys for your healthcheck projects. (Read-only works fine)
- type: HealthChecks  options:    host: https://healthcheck.your-domain.de    apiKey:       - abcdefg...      - zxywvu...

Info#


Hackernews Trending#

Display new and trending Posts from Hackernews

Options#

FieldTypeRequiredDescription
storiesstringOptionalHN Stories to display defaults to topstories. Options are: beststories, topstories or newstories
limitintOptionalThe size of the list of Posts to show.
Example#
- type: hackernews-trending  options:    stories: newstories    limit: 10

MVG Departure#

Display departure time of a MVG (Münchner Verkehrs Gesellschaft) station.

From https://www.mvg.de/impressum.html:

[...] Die Verarbeitung unserer Inhalte oder Daten durch Dritte erfordert unsere ausdrückliche Zustimmung. Für private, nicht-kommerzielle Zwecke, wird eine gemäßigte Nutzung ohne unsere ausdrückliche Zustimmung geduldet. Jegliche Form von Data-Mining stellt keine gemäßigte Nutzung dar.[...]

In other words: Private, noncomercial, moderate use of the API is tolerated. They don’t consider data mining as moderate use. (This is not a legal advice)

Options#

FieldTypeRequiredDescription
locationstringRequiredThe name of the location (exact) or the location id, startin with de:09162:
limitintegerOptionalLimit number of entries, defaults to 10.
titlestringOptionalA custom title to be displayed.
headerboolOptionalShall the title be shown?
filtersobjectOptionalFilter results
filters.linestring/arrayOptionalFilter results for given line(s).
filters.productstring/arrayOptionalFilter results for specific product (TRAM, UBAHN, SBAHN, BUS).
filters.destinationstring/objectOptionalFilter results for specific destination(s)
- type: mvg  options:    location: Marienplatz    limit: 5

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Not Required
  • Price: 🟢 Free / Private use only
  • Host: MVG
  • Privacy: See MVG Datenschutz

MVG Connection#

Display the next connection for two addresses/coordinates, stations or POI within Munich using MVG MVG (Münchner Verkehrs Gesellschaft).

From https://www.mvg.de/impressum.html:

[...] Die Verarbeitung unserer Inhalte oder Daten durch Dritte erfordert unsere ausdrückliche Zustimmung. Für private, nicht-kommerzielle Zwecke, wird eine gemäßigte Nutzung ohne unsere ausdrückliche Zustimmung geduldet. Jegliche Form von Data-Mining stellt keine gemäßigte Nutzung dar.[...]

In other words: Private, noncomercial, moderate use of the API is tolerated. They don’t consider data mining as moderate use. (This is not a legal advice)

Options#

FieldTypeRequiredDescription
originstringRequiredOrigin of the connection.
destinationstringRequiredDestination of the connection.
titlestringOptionalA custom title to be displayed.
headerboolOptionalShall the title be shown?
filtersobjectOptionalFilter results
filters.linestring/arrayOptionalFilter results for given line(s).
filters.productstring/arrayOptionalFilter results for specific product (TRAM, UBAHN, SBAHN, BUS).
filters.destinationstring/objectOptionalFilter results for specific destination(s)
- type: mvg-connection  options:    from: Marienplatz    from: Dachauer Straße 123    header: true    filters:      product: [UBAHN]      line: [U1,U2,U4,U5]
 

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Not Required
  • Price: 🟢 Free / Private use only
  • Host: MVG
  • Privacy: See MVG Datenschutz

Custom search#

Allows web search using multiple user-defined search engines and other websites.

Options#

FieldTypeRequiredDescription
enginesarrayrequiredAn array of search engine objects. Each search engine object should have two required properties: title and url. See the example below.
placeholderstringoptionalPlaceholder text in the search box.

Notes#

  • The first search engine in the engines array will be treated as the default search engine, and used when the user presses Enter in the search box.
  • Popup blockers can interfere with opening a new search window.

Example#

This widget allows searching multiple search engines from dashy.

  - type: 'custom-search'    options:      placeholder: Search for something using the buttons below      engines:      - title: SearXNG        url: https://searx.lan/?q=      - title: Quant        url: https://www.qwant.com/?q=      - title: Bing Web        url: http://www.bing.com/search?q=      - title: Bing Images        url: http://www.bing.com/images/search?q=      - title: Bing Maps        url: http://www.bing.com/maps/search?q=      - title: Yandex        url: https://www.yandex.com/search/?text=      - title: Passmark        url: https://www.passmark.com/search/zoomsearch.php?zoom_query=      - title: IMDB        url: http://www.imdb.com/find?q=

Info#

  • CORS: 🟢 Not needed
  • Auth: 🟢 Not Required
  • Price: 🟢 Free
  • Host: user defined
  • Privacy: depends on the user defined search engines.

RescueTime Overview#

Show an overview of how you have spent your time for the current day.

Options#

FieldTypeRequiredDescription
apiKeystringrequiredThe API-Key generated in the RescueTime UI.

Example#

  - type: rescue-time    useProxy: true    options:      apiKey: abcdefghijkl_mnop

Info#


Self-Hosted Services Widgets#

System Info#

See MVG Datenschutz Displays info about the server which Dashy is hosted on. Includes user + host, operating system, uptime and basic memory & load data.

Options#

No config options.

Example#

- type: system-info

Info#

No external data requests made

Note that this widget is not available if you are running Dashy in a container or VM. Instead you can use the System Monitoring widgets to display stats from the host system instead.


Cron Monitoring (Health Checks)#

Cron job monitoring using Health Checks. Both managed and self-hosted instances are supported.

Options#

FieldTypeRequiredDescription
apiKeystringRequiredA read-only API key for the project to monitor. You can generate this by selecting a Project --> Settings --> API Access. Note that you must generate a separate key for each project
hoststringOptionalIf you're self-hosting, or using any instance other than the official (healthchecks.io), you will need to specify the host address. E.g. https://healthchecks.example.com or http://cron-monitoing.local

Example#

- type: health-checks  options:    apiKey: XXXXXXXXX

Info#


CPU History (NetData)#

Pull recent CPU usage history from NetData.

Options#

FieldTypeRequiredDescription
hoststringRequiredThe URL to your NetData instance
chartHeightnumberOptionalThe height of rendered chart in px. Defaults to 300
chartColor / chartColorsstring / arrayOptionalColor of the chart value(s) as hex codes. chartColor is a single value (defaults to --widget-text-color), whereas chartColors is an array of colors

Example#

- type: nd-cpu-history  options:  host: http://192.168.1.1:19999

Info#


Memory History (NetData)#

Pull recent system RAM usage from NetData, and show as a breakdown of different categories.

Options#

FieldTypeRequiredDescription
hoststringRequiredThe URL to your NetData instance
chartHeightnumberOptionalThe height of rendered chart in px. Defaults to 300
chartColor / chartColorsstring / arrayOptionalColor of the chart value(s) as hex codes. chartColor is a single value (defaults to --widget-text-color), whereas chartColors is an array of colors

Example#

- type: nd-ram-history  options:    host: http://192.168.1.1:19999

Info#


Load History (NetData)#

Pull recent load usage in 1, 5 and 15 minute intervals, from NetData.

Options#

FieldTypeRequiredDescription
hoststringRequiredThe URL to your NetData instance
chartHeightnumberOptionalThe height of rendered chart in px. Defaults to 300
chartColor / chartColorsstring / arrayOptionalColor of the chart value(s) as hex codes. chartColor is a single value (defaults to --widget-text-color), whereas chartColors is an array of colors

Example#

- type: nd-load-history  options:  host: http://192.168.1.1:19999

Info#


Pi Hole Stats#

Displays the number of queries blocked by Pi-Hole.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your Pi-Hole instance
hideStatus / hideChart / hideInfobooleanOptionalOptionally hide any of the three parts of the widget
apiKeystringRequiredYour Pi-Hole web password. It is NOT your pi-hole admin interface or server password. It can be found in /etc/pihole/setupVars.conf, and is a 64-character located on the line that starts with WEBPASSWORD

Example#

- type: pi-hole-stats  options:    hostname: http://192.168.130.1    apiKey: xxxxxxxxxxxxxxxxxxxxxxx

Info#


Pi Hole Queries#

Shows top queries that were blocked and allowed by Pi-Hole.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your Pi-Hole instance
apiKeystringRequiredYour Pi-Hole web password. It is NOT your pi-hole admin interface or server password. It can be found in /etc/pihole/setupVars.conf, and is a 64-character located on the line that starts with WEBPASSWORD
countnumberOptionalThe number of queries to display. Defaults to 10

Example#

- type: pi-hole-top-queries  options:    hostname: https://pi-hole.local    apiKey: xxxxxxxxxxxxxxxxxxxxxxx

Info#


Pi Hole Recent Traffic#

Shows number of recent traffic, using allowed and blocked queries from Pi-Hole

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your Pi-Hole instance
apiKeystringRequiredYour Pi-Hole web password. It is NOT your pi-hole admin interface or server password. It can be found in /etc/pihole/setupVars.conf, and is a 64-character located on the line that starts with WEBPASSWORD

Example#

- type: pi-hole-traffic  options:    hostname: https://pi-hole.local    apiKey: xxxxxxxxxxxxxxxxxxxxxxx

Info#


Stat Ping Statuses#

Displays the current and recent uptime of your running services, via a self-hosted instance of StatPing

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your StatPing instance, without a trailing slash
groupIdnumberOptionalIf provided, only Services in the given group are displayed. Defaults to 0 in which case all services are displayed.
showChartbooleanOptionalIf provided and false then charts are not displayed. Defaults to true.
showInfobooleanOptionalIf provided and false then information summaries are not displayed. Defaults to true.

Example#

- type: stat-ping  options:    hostname: http://192.168.130.1:8080

or

- type: stat-ping  options:    hostname: http://192.168.130.1:8080    groupId: 3    showChart: false    showInfo: false

You can use multiple StatPing widgets with different groupIds.

Note, the Group Id is not directly visible in StatPing UI, you can inspect the group select HTML element or the API response to find out.

Info#


Synology Download Station#

Displays the current downloads/torrents tasks of your Synology NAS

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your Synology NAS, without a trailing slash
usernamestringRequiredThe username of a user on your synology NAS. You will see only this user download station tasks if he is not part of the administrator group. Currently don't support OTP protected accounts.
passwordstringRequiredThe password of the account specified above.

Example#

- type: synology-download  options:    hostname: http://192.168.1.1:8080    username: dashy    password: totally-secure-password
 
 

Info#


AdGuard Home Block Stats#

Fetches data from your AdGuard Home instance, and -displays total number of allowed and blocked queries, plus a pie chart showing breakdown by block type.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your AdGuard Home instance
usernamestringOptionalIf you've got auth enabled on AdGuard, provide your username here
passwordstringOptionalIf you've got auth enabled on AdGuard, provide your password here

Example#

- type: adguard-stats  useProxy: true  options:    hostname: http://127.0.0.1    username: admin    password: test

Info#


AdGuard Home Filters#

Fetches data from your AdGuard Home instance, to display the current status of each of your filter lists. Includes filter name, last updated, number of items, and a link to the list.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your AdGuard Home instance
usernamestringOptionalIf you've got auth enabled on AdGuard, provide your username here
passwordstringOptionalIf you've got auth enabled on AdGuard, provide your password here
showOnOffStatusOnlybooleanOptionalIf set to true, will only show aggregated AdGuard filter status (on/off), instead of a list of filters

Example#

- type: adguard-filter-status  useProxy: true  options:    hostname: http://127.0.0.1    username: admin    password: test    showOnOffStatusOnly: false

Info#


AdGuard Home DNS Info#

Fetches data from your AdGuard Home instance, and displays the current status (Enabled / Disabled) of AdGuard DNS. Click show more to view detailed info, including upstream DNS provider, active ports, and the status of DNSSEC, EDNS CS, PTR and IPv6.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your AdGuard Home instance
usernamestringOptionalIf you've got auth enabled on AdGuard, provide your username here
passwordstringOptionalIf you've got auth enabled on AdGuard, provide your password here
showFullInfobooleanOptionalIf set to true, the full DNS info will be shown by default, without having to click "Show Info"

Example#

- type: adguard-dns-info  useProxy: true  options:    hostname: http://127.0.0.1    username: admin    password: test    showFullInfo: false

Info#


AdGuard Home Top Domains#

Fetches data from your AdGuard Home instance, and displays a list of the most queried, and most blocked domains.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your AdGuard Home instance
usernamestringOptionalIf you've got auth enabled on AdGuard, provide your username here
passwordstringOptionalIf you've got auth enabled on AdGuard, provide your password here
limitnumberOptionalSpecify the number of results to show, between 1 and 100, defaults to 10
hideBlockedDomainsbooleanOptionalDon't show the blocked domains list (queried domains only)
hideQueriedDomainsbooleanOptionalDon't show the queried domains list (blocked domains only)

Example#

- type: adguard-top-domains  useProxy: true  options:    hostname: http://127.0.0.1    username: admin    password: test    limit: 10

Info#


Nextcloud User#

Nextcloud is a self hosted productivity platform, it can also be used free of charge with hundreds of existing hosting providers that offer a free Nextcloud account.

Displays branding information of a Nextcloud server (logo, url, slogan) and some user details (name, login name, last login, disk space or quota). Use with regular or admin user.

Shows quota usage when quota is enabled for the user or disk usage when not enabled.

Known issues: the User API incorrectly reports available disk space as total for admin users when quota is not enabled (which usually is the case for admins).

nextcloud-user

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredNextcloud username
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)

Example#

- type: nextcloud-user  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx

Info#


Nextcloud User Statuses#

Show user statuses for selected users.

nextcloud-userstatus

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredNextcloud username
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)
usersarrayRequiredNextcloud User IDs to show statuses for, list size between 1 and 100
showEmptybooleanOptionalShow statuses without a message, defaults to true

Example#

- type: nextcloud-userstatus  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx    users: ['bob', 'alice']

Info#


Nextcloud Notifications#

Displays your notifications and allows deleting them.

nextcloud-notifications

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredNextcloud username
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)
limitnumber\|stringOptionalLimit displayed notifications either by count, e.g. 5 to show the 5 most recent, or by age, e.g. 1d to only show notifications not older than a day. Accepted suffixes for age limit are m, h and d.

Example#

- type: nextcloud-notifications  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx    limit: 6h

Info#


Nextcloud System#

Visualises overall memory utilisation and CPU load averages, shows server versions.

nextcloud-system

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredMust be a Nextcloud admin user
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)

Example#

- type: nextcloud-system  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx

Info#


Nextcloud Stats#

Shows key usage statistics about your Nextcloud server.

nextcloud-stats

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredMust be a Nextcloud admin user
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)

Example#

- type: nextcloud-stats  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx

Info#


Nextcloud PHP OPcache Stats#

Shows statistics about PHP OPcache performance on your Nextcloud server.

nextcloud-phpopcache

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredMust be a Nextcloud admin user
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)

Example#

- type: nextcloud-php-opcache  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx

Info#


Proxmox lists#

Shows lists of nodes, containers, and VMs in a Proxmox virtual environment cluster, with a status indicator.

Options#

FieldTypeRequiredDescription
cluster_urlstringRequiredThe URL of the proxmox cluster server. No trailing /. for example: https://proxmox.lan:8006
user_namestringRequiredA Proxmox API Username, for example root@pam or dashy@pve.
token_namestringRequiredA Proxmox API token name. You can get a token in the API section of the cluster management interface.
token_uuidstringRequiredThe value of the token entered above. This is normally a UUID.
nodestringoptionalA Proxmox node name. If empty or not supplied, a list of nodes will be shown.
node_datastringoptionalThis is required if a node is selected, Currently this accepts two values, either lxc or qemu but the widget can be improved to get other types of data from the Proxmox API.
titlestringoptionalA widget title.
title_as_linkbooleanoptionalWhen this is set to anything other than 0 or false, the title will be linked to the value entered in the cluster_url option.
footerstringoptionalA widget footer.
footer_as_linkbooleanoptionalWhen this is set to anything other than 0 or false, the title will be linked to the value entered in the cluster_url option.
hide_templatesbooleanoptionalWhen this is set to anything other than 0 or false, templates will be filtered out of the result list.

Example#

This will show the list of nodes.

  - type: proxmox-lists    useProxy: true     options:      cluster_url: https://proxmox.lan:8006      user_name: root@pam      token_name: dashy      token_uuid: bfb152df-abcd-abcd-abcd-ccb95a472d01

This will show the list of VMs, with a title and a linked fotter, hiding VM templates.

  - type: proxmox-lists    useProxy: true     options:      cluster_url: https://proxmox.lan:8006      user_name: root@pam      token_name: dashy      token_uuid: bfb152df-abcd-abcd-abcd-ccb95a472d01      node: proxmox      node_data: qemu      title: Proxmox VMs      title_as_link: false      footer: Proxmox      footer_as_link: true      hide_templates: 1

Troubleshooting#

  • 404 Error in development mode: The error might disappear in production mode yarn start
  • 500 Error in production mode: Try adding the certificate authority (CA) certificate of your Proxmox host to Node.js.
    • Download the Proxmox CA certificate to your Dashy host.
    • Export environment variable NODE_EXTRA_CA_CERTS and set its value to the path of the downloaded CA certificate. Example: export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/devlab_ca.pem

Info#


Sabnzbd#

Shows queue information regarding your self hosted Sabnzbd server.

Sabnzbd

Options#

FieldTypeRequiredDescription
sabnzbdUrlstringRequiredThe URL of the Sabnzbd server. No trailing /.
apiKeystringRequiredAPI key for Sabnzbd access. Located under Config -> General -> Security -> API Key.
hideDetailsbooleanOptionalHides extra server queue details.
hideQueuebooleanOptionalHides the queue list in an expandable dropdown.

Example#

  - type: sabnzbd    options:      sabnzbdUrl: 'https://sabnzbd.example.com'      apiKey: XXXXXXXXXXXXXXXXXX      hideDetails: false      hideQueue: false

Info#


Gluetun VPN Info#

Display info from the Gluetun VPN container public IP API. This can show the IP and location data for the exit VPN node.

Options#

FieldTypeRequiredDescription
visibleFieldsstringRequiredA comma separated list of the fields you want visible in the widget. You can have any number of the following : public_ip, region, country, city, location, organisation, postal_code, timezone. Defaults to just public_ip
hoststringRequiredThe url to the gluetun HTTP control server. E.g. http://gluetun:8000

Example#

- type: gluetun-status  useProxy: true  options:    hostname: http://server-or-conatiner-hostname:8000    visibleFields: public_ip,region,country,city,location,organisation,postal_code,timezone

Info#

  • CORS: 🟠 Proxied
  • Auth: 🟢 Required
  • Price: 🟢 Free
  • Host: Self-Hosted (see Gluetun)
  • Privacy: See Gluetun Wiki

Drone CI Builds#

Display the last builds from a Drone CI instance. A self-hosted CI system that uses docker.

Options#

FieldTypeRequiredDescription
hoststringRequiredThe hostname of the Drone CI instance.
apiKeystringRequiredThe API key (https://[your-drone-instance]/account).
limitintegerOptionalLimit the amounts of listed builds.
repostringOptionalShow only builds of the specified repo

Example#

- type: drone-io  updateInterval: 30  options:    host: https://drone.somedomain.com    apiKey: my-very-secret-api-key    limit: 10

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Required
  • Price: 🟢 Free
  • Host: Self-Hosted (see Drone)
  • Privacy: See Drone

Linkding#

Linkding is a self-hosted bookmarking service, which has a clean interface and is simple to set up. This lists the links, filterable by tags.

Options#

FieldTypeRequiredDescription
hoststringRequiredThe hostname of the Drone CI instance.
apiKeystringRequiredThe API key (https://your-linkding-instance/settings/integrations).
tagslist of stringOptionalFilter the links by tag.

Example#

- type: linkding  updateInterval: 30  options:    host: https://lingding.somedomain.com    apiKey: my-very-secret-api-key    tags:       - rpg      - markdown

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Required
  • Price: 🟢 Free
  • Host: Self-Hosted (see Linkding)
  • Privacy: See Linkding

System Resource Monitoring#

Glances#

The easiest method for displaying system info and resource usage in Dashy is with Glances.

Glances is a cross-platform monitoring tool developed by @nicolargo. It's similar to top/htop but with a Rest API and many data exporters available. Under the hood, it uses psutil for retrieving system info.

If you don't already have it installed, either follow the Installation Guide for your system, or setup with Docker, or use the one-line install script: curl -L https://bit.ly/glances | /bin/bash.

If you are using Docker to run glances make sure to add the enviroment variable -e TZ = {YourTimeZone}. You can get a list of valid timezones by running timedatectl list-timezones on any linux system. This is needed so the graphs show the currect time.

Here an example for Docker

 docker run -d \    --name glances \    --restart unless-stopped \    -v /var/run/docker.sock:/var/run/docker.sock:ro \    -p 61208:61208 \    --pid host \    --privileged \    -e GLANCES_OPT=-w \    -e PUID=1000 \    -e PGID=1000 \    -e TZ=Europe/Zurich \    nicolargo/glances:latest

Glances can be launched with the glances command. You'll need to run it in web server mode, using the -w option for the API to be reachable. If you don't plan on using the Web UI, then you can disable it using --disable-webui. See the command reference docs for more info.

If Glaces is running on a Windows system it is recommanded to add the following arguments --disable-plugin all --enable-plugin cpu,mem,diskio,ip,network,containers,quicklook,load,fs,alert -w This is due to Glances not being that stable on windows, so disabling all plugins that aren't used by Dashy widgets can save on ressources.

Options#

All Glance's based widgets require a hostname. All other parameters are optional.

FieldTypeRequiredDescription
hostnamestringRequiredThe URL or IP + port to your Glances instance (without a trailing slash)
usernamestringOptionalIf you have setup basic auth on Glances, specify username here (defaults to glances)
passwordstringOptionalIf you have setup basic auth on Glances, specify password here. Note: since this password is in plaintext, it is important not to reuse it anywhere else
apiVersionstringOptionalSpecify an API version, defaults to V 3. Note that support for older versions is limited
limitnumberOptionalFor widgets that show a time-series chart, optionally limit the number of data points returned. A higher number will show more historical results, but will take longer to load. A value between 300 - 800 is usually optimal

Note that if auth is configured, requests must be proxied with useProxy: true

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟠 Optional
  • Price: 🟢 Free
  • Host: Self-Hosted (see GitHub - Nicolargo/Glances)
  • Privacy: ⚫ No Policy Available

Screenshot#

example-screenshot


Current CPU Usage#

Live-updating current CPU usage, as a combined average across all cores

Example#

- type: gl-current-cpu  options:    hostname: http://192.168.130.2:61208

Current CPU Usage Speedometer#

Speedometer styled version of the Current CPU Usage widget

Example#

- type: gl-cpu-speedometer  options:    hostname: http://192.168.130.2:61208

CPU Usage Per Core#

Live-updating CPU usage breakdown per core

Example#

- type: gl-current-cores  options:    hostname: http://192.168.130.2:61208

CPU Usage History#

Recent CPU usage history, across all cores, and displayed by user and system

Options#

FieldTypeRequiredDescription
limitnumberOptionalLimit the number of results returned, rendering more data points will take longer to load. Defaults to 100

Example#

- type: gl-cpu-history  options:    hostname: http://192.168.130.2:61208    limit: 60

Current Memory Usage#

Real-time memory usage gauge, with more info visible on click

Example#

- type: gl-current-mem  options:    hostname: http://192.168.130.2:61208

Current Memory Usage Speedometer#

Speedometer styled version of the Current Memory Usage widget

Example#

- type: gl-mem-speedometer  options:    hostname: http://192.168.130.2:61208

Memory Usage History#

Recent memory usage chart

Options#

FieldTypeRequiredDescription
limitnumberOptionalLimit the number of results returned, rendering more data points will take longer to load. Defaults to 100

Example#

- type: gl-mem-history  options:    hostname: http://localhost:61208    limit: 80

Disk Space#

List connected disks, showing free / used space and other info (file system, mount point and space available)

Example#

- type: gl-disk-space  options:    hostname: http://192.168.130.2:61208

Disk IO#

Shows real-time read and write speeds and operations per sec for each disk

Example#

- type: gl-disk-io  options:    hostname: http://192.168.130.2:61208

System Load#

Shows the number of processes waiting in the run-queue, averaged across all cores. Displays for past 5, 10 and 15 minutes

Example#

- type: gl-system-load  options:    hostname: http://192.168.130.2:61208

System Load History#

Shows recent historical system load, calculated from the number of processes waiting in the run-queue, in 1, 5 and 15 minute intervals, and averaged across all cores. Optionally specify limit to set number of results returned, defaults to 500, max 100000, but the higher the number the longer the load and render times will be.

Example#

- type: gl-load-history  options:    hostname: http://192.168.130.2:61208

Network Interfaces#

Lists visible network interfaces, including real-time upload/ download stats

Example#

- type: gl-network-interfaces  options:    hostname: http://192.168.130.2:61208

Network Traffic#

Shows amount of data recently uploaded/ downloaded across all network interfaces. Optionally set the limit option to specify number historical of data points to return

Example#

- type: gl-network-traffic  options:    hostname: http://192.168.130.2:61208    limit: 500

Resource Usage Alerts#

Lists recent high resource usage alerts (e.g. CPU, mem, IO, load, temp)

Example#

- type: gl-alerts  options:    hostname: http://192.168.130.2:61208

IP Address#

Shows public and private IP address. Note that the ip plugin is not available on all instances of Glances.

Example#

- type: gl-ip-address  options:    hostname: http://192.168.130.2:61208

CPU Temp#

Displays temperature data from system CPUs.

Note: This widget uses the sensors plugin, which is disabled by default, and may cause performance issues. -You'll need to enable the sensors plugin to use this widget, using: --enable-plugin sensors when you start Glances.

Options#

FieldTypeRequiredDescription
unitsstringOptionalUse C to display temperatures in Celsius or F to use Fahrenheit. Defaults to C.

Example#

- type: gl-cpu-temp  options:    hostname: http://192.168.130.2:61208    units: C

Dynamic Widgets#

Iframe Widget#

Embed any webpage into your dashboard as a widget.

Options#

FieldTypeRequiredDescription
urlstringRequiredThe URL to the webpage to embed
frameHeightnumberOptionalIf needed, specify height of iframe in px. E.g. 400, defaults to auto

Example#

- type: iframe  options:    url: https://fiatleak.com/

HTML Embedded Widget#

Many websites and apps provide their own embeddable widgets. These can be used with Dashy using the Embed widget, which lets you dynamically embed and HTML, CSS or JavaScript contents.

⚠️ NOTE: Use with extreme caution. Embedding a script from an untrustworthy source may have serious unintended consequences.

Options#

FieldTypeRequiredDescription
htmlstringOptionalHTML contents to render in the widget
scriptstringOptionalRaw JavaScript code to execute (caution)
scriptSrcstringOptionalA URL to JavaScript content (caution)
cssstringOptionalAny stylings for widget contents

Example#

- type: embed  options:    scriptSrc: https://cdn.speedcheck.org/basic/scbjs.min.js    html: |      <div id="sc-container">      <div id="sc-branding" class="sc-bb">      <a target="_blank" href="https://www.speedcheck.org/">      <img src="https://cdn.speedcheck.org/branding/speedcheck-logo-18.png" alt="Speedcheck"/>      </a>      </div>      </div>

Or

- type: embed    options:      css: '.coinmarketcap-currency-widget { color: var(--widget-text-color); }'      html: '<div class="coinmarketcap-currency-widget" data-currencyid="1" data-base="USD" data-secondary="" data-ticker="true" data-rank="true" data-marketcap="true" data-volume="true" data-statsticker="true" data-stats="USD"></div>'      scriptSrc: 'https://files.coinmarketcap.com/static/widget/currency.js'

You can also use this widget to display an image, wither locally or from a remote origin.

- type: embed  options:    html: '<img src="https://dashy.lan/item-icons/my-image.png" />'

API Response#

Directly output plain-text response from any API-enabled service.

// Coming soon...


Prometheus Data#

Display data from any service with a Prometheus exporter.

// Coming soon...


Data Feed#

Show live data from an RSS-enabled service. The only required parameter is rssUrl, which is the URL to the ATOM feed. See RSS Widget for full list of available options.

Example#

- type: rss-feed  options:    rssUrl: https://notes.aliciasykes.com/feed

Usage & Customizations#

Widget Usage Guide#

Like items, widgets are placed under sections. You may have one or more widgets per section.

In your YAML config file, this will look something like:

sections:- name: Today  icon: far fa-calendar-day  widgets:  - type: clock    options:      format: en-GB  - type: weather    options:      apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      city: London      units: metric

In this example, there is a single section, named "Today", using a Calendar icon from Font-Awesome. It has 2 widgets, a clock and the current weather.


Continuous Updates#

By default, a widget which displays dynamic data from an external source, will only fetch results on page load. If you would like to keep data updated at all times, you can enable Continuous Updates. This is done by setting a time value in the updateInterval field.

The value of updateInterval is optional, and is specified and seconds. It must be more than 10 and less than 7200.

For example, the following widget displaying stats from Pi-Hole will update ever 20 seconds.

widgets:- type: pi-hole-stats  updateInterval: 20  options:    hostname: http://192.168.130.2

Note that if you have many widgets, and set them to continuously update frequently, you will notice a hit to performance. A widget that relies on data from an external API, will also consume your usage quota faster, if set to keep updating.


Proxying Requests#

If a widget fails to make a data request, and the console shows a CORS error, this means the server is blocking client-side requests.

Dashy has a built-in CORS proxy (services/cors-proxy.js), which will be used automatically by some widgets, or can be forced to use by other by setting the useProxy option.

For example:

widgets:- type: pi-hole-stats  useProxy: true  options:    hostname: http://pi-hole.local

Alternatively, and more securely, you can set the auth headers on your service to accept requests from Dashy. For example:

Access-Control-Allow-Origin: https://location-of-dashy/Vary: Origin

Setting Timeout#

If the endpoint you are requesting data from is slow to respond, you may see a timeout error in the console. This can easily be fixed by specifying the timeout property on the offending widget. This should be an integer value, in milliseconds. By default timeout is 2500 ms (2½ seconds).

For example:

- type: gl-current-cpu  timeout: 8000  options:    hostname: https://glances.dns-device.local

Adding Labels#

If you have multiple widgets of the same type in a single section, it may not be clear what each one is. To overcome this, you can add a custom label to any given widget, using the label property.

For example:

- name: CPU Usage  icon: fas fa-tachometer  widgets:  - type: gl-current-cpu    label: Meida Server    options:      hostname: http://media-server.lan:61208  - type: gl-current-cpu    label: Firewall    options:      hostname: http://firewall.lan:61208  - type: gl-current-cpu    label: File Sync Server    options:      hostname: http://file-sync.lan:61208

Ignoring Errors#

When there's an error fetching or displaying a widgets data, then it will be highlighted in yellow, and a message displayed on the UI.

In some instances, this is a false positive, and the widget is actually functioning correctly. If this is the case, you can disable the UI error message of a given widget by setting: ignoreErrors: true

- type: gl-disk-io  ignoreErrors: true  options:    hostname: https://glances.dns-device.local

Widget Styling#

Like elsewhere in Dashy, all colours can be easily modified with CSS variables.

Widgets use the following color variables, which can be overridden if desired:

  • --widget-text-color - Text color, defaults to --primary
  • --widget-background-color - Background color, defaults to --background-darker
  • --widget-accent-color - Accent color, defaults to --background

For more info on how to apply custom variables, see the Theming Docs


Customizing Charts#

For widgets that contain charts, you can set an array of colors under chartColors. +displays total number of allowed and blocked queries, plus a pie chart showing breakdown by block type.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your AdGuard Home instance
usernamestringOptionalIf you've got auth enabled on AdGuard, provide your username here
passwordstringOptionalIf you've got auth enabled on AdGuard, provide your password here

Example#

- type: adguard-stats  useProxy: true  options:    hostname: http://127.0.0.1    username: admin    password: test

Info#


AdGuard Home Filters#

Fetches data from your AdGuard Home instance, to display the current status of each of your filter lists. Includes filter name, last updated, number of items, and a link to the list.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your AdGuard Home instance
usernamestringOptionalIf you've got auth enabled on AdGuard, provide your username here
passwordstringOptionalIf you've got auth enabled on AdGuard, provide your password here
showOnOffStatusOnlybooleanOptionalIf set to true, will only show aggregated AdGuard filter status (on/off), instead of a list of filters

Example#

- type: adguard-filter-status  useProxy: true  options:    hostname: http://127.0.0.1    username: admin    password: test    showOnOffStatusOnly: false

Info#


AdGuard Home DNS Info#

Fetches data from your AdGuard Home instance, and displays the current status (Enabled / Disabled) of AdGuard DNS. Click show more to view detailed info, including upstream DNS provider, active ports, and the status of DNSSEC, EDNS CS, PTR and IPv6.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your AdGuard Home instance
usernamestringOptionalIf you've got auth enabled on AdGuard, provide your username here
passwordstringOptionalIf you've got auth enabled on AdGuard, provide your password here
showFullInfobooleanOptionalIf set to true, the full DNS info will be shown by default, without having to click "Show Info"

Example#

- type: adguard-dns-info  useProxy: true  options:    hostname: http://127.0.0.1    username: admin    password: test    showFullInfo: false

Info#


AdGuard Home Top Domains#

Fetches data from your AdGuard Home instance, and displays a list of the most queried, and most blocked domains.

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL to your AdGuard Home instance
usernamestringOptionalIf you've got auth enabled on AdGuard, provide your username here
passwordstringOptionalIf you've got auth enabled on AdGuard, provide your password here
limitnumberOptionalSpecify the number of results to show, between 1 and 100, defaults to 10
hideBlockedDomainsbooleanOptionalDon't show the blocked domains list (queried domains only)
hideQueriedDomainsbooleanOptionalDon't show the queried domains list (blocked domains only)

Example#

- type: adguard-top-domains  useProxy: true  options:    hostname: http://127.0.0.1    username: admin    password: test    limit: 10

Info#


Nextcloud User#

Nextcloud is a self hosted productivity platform, it can also be used free of charge with hundreds of existing hosting providers that offer a free Nextcloud account.

Displays branding information of a Nextcloud server (logo, url, slogan) and some user details (name, login name, last login, disk space or quota). Use with regular or admin user.

Shows quota usage when quota is enabled for the user or disk usage when not enabled.

Known issues: the User API incorrectly reports available disk space as total for admin users when quota is not enabled (which usually is the case for admins).

nextcloud-user

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredNextcloud username
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)

Example#

- type: nextcloud-user  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx

Info#


Nextcloud User Statuses#

Show user statuses for selected users.

nextcloud-userstatus

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredNextcloud username
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)
usersarrayRequiredNextcloud User IDs to show statuses for, list size between 1 and 100
showEmptybooleanOptionalShow statuses without a message, defaults to true

Example#

- type: nextcloud-userstatus  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx    users: ['bob', 'alice']

Info#


Nextcloud Notifications#

Displays your notifications and allows deleting them.

nextcloud-notifications

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredNextcloud username
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)
limitnumber\|stringOptionalLimit displayed notifications either by count, e.g. 5 to show the 5 most recent, or by age, e.g. 1d to only show notifications not older than a day. Accepted suffixes for age limit are m, h and d.

Example#

- type: nextcloud-notifications  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx    limit: 6h

Info#


Nextcloud System#

Visualises overall memory utilisation and CPU load averages, shows server versions.

nextcloud-system

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredMust be a Nextcloud admin user
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)

Example#

- type: nextcloud-system  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx

Info#


Nextcloud Stats#

Shows key usage statistics about your Nextcloud server.

nextcloud-stats

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredMust be a Nextcloud admin user
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)

Example#

- type: nextcloud-stats  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx

Info#


Nextcloud PHP OPcache Stats#

Shows statistics about PHP OPcache performance on your Nextcloud server.

nextcloud-phpopcache

Options#

FieldTypeRequiredDescription
hostnamestringRequiredThe URL of the Nextcloud server
usernamestringRequiredMust be a Nextcloud admin user
passwordstringRequiredNextcloud app-password (create one in Settings -> Security)

Example#

- type: nextcloud-php-opcache  useProxy: true  options:    hostname: https://nextcloud.example.com    username: alice    password: xxxxx-xxxxx-xxxxx-xxxxx

Info#


Proxmox lists#

Shows lists of nodes, containers, and VMs in a Proxmox virtual environment cluster, with a status indicator.

Options#

FieldTypeRequiredDescription
cluster_urlstringRequiredThe URL of the proxmox cluster server. No trailing /. for example: https://proxmox.lan:8006
user_namestringRequiredA Proxmox API Username, for example root@pam or dashy@pve.
token_namestringRequiredA Proxmox API token name. You can get a token in the API section of the cluster management interface.
token_uuidstringRequiredThe value of the token entered above. This is normally a UUID.
nodestringoptionalA Proxmox node name. If empty or not supplied, a list of nodes will be shown.
node_datastringoptionalThis is required if a node is selected, Currently this accepts two values, either lxc or qemu but the widget can be improved to get other types of data from the Proxmox API.
titlestringoptionalA widget title.
title_as_linkbooleanoptionalWhen this is set to anything other than 0 or false, the title will be linked to the value entered in the cluster_url option.
footerstringoptionalA widget footer.
footer_as_linkbooleanoptionalWhen this is set to anything other than 0 or false, the title will be linked to the value entered in the cluster_url option.
hide_templatesbooleanoptionalWhen this is set to anything other than 0 or false, templates will be filtered out of the result list.

Example#

This will show the list of nodes.

  - type: proxmox-lists    useProxy: true     options:      cluster_url: https://proxmox.lan:8006      user_name: root@pam      token_name: dashy      token_uuid: bfb152df-abcd-abcd-abcd-ccb95a472d01

This will show the list of VMs, with a title and a linked fotter, hiding VM templates.

  - type: proxmox-lists    useProxy: true     options:      cluster_url: https://proxmox.lan:8006      user_name: root@pam      token_name: dashy      token_uuid: bfb152df-abcd-abcd-abcd-ccb95a472d01      node: proxmox      node_data: qemu      title: Proxmox VMs      title_as_link: false      footer: Proxmox      footer_as_link: true      hide_templates: 1

Info#

Troubleshooting#

  • 404 Error in development mode: The error might disappear in production mode yarn start
  • 500 Error in production mode: Try adding the certificate authority (CA) certificate of your Proxmox host to Node.js.
    • Download the Proxmox CA certificate to your Dashy host.
    • Export environment variable NODE_EXTRA_CA_CERTS and set its value to the path of the downloaded CA certificate. Example: export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/devlab_ca.pem

Sabnzbd#

Shows queue information regarding your self hosted Sabnzbd server.

Sabnzbd

Options#

FieldTypeRequiredDescription
sabnzbdUrlstringRequiredThe URL of the Sabnzbd server. No trailing /.
apiKeystringRequiredAPI key for Sabnzbd access. Located under Config -> General -> Security -> API Key.
hideDetailsbooleanOptionalHides extra server queue details.
hideQueuebooleanOptionalHides the queue list in an expandable dropdown.

Example#

  - type: sabnzbd    options:      sabnzbdUrl: 'https://sabnzbd.example.com'      apiKey: XXXXXXXXXXXXXXXXXX      hideDetails: false      hideQueue: false

Info#


Gluetun VPN Info#

Display info from the Gluetun VPN container public IP API. This can show the IP and location data for the exit VPN node.

Options#

FieldTypeRequiredDescription
visibleFieldsstringRequiredA comma separated list of the fields you want visible in the widget. You can have any number of the following : public_ip, region, country, city, location, organisation, postal_code, timezone. Defaults to just public_ip
hoststringRequiredThe url to the gluetun HTTP control server. E.g. http://gluetun:8000

Example#

- type: gluetun-status  useProxy: true  options:    hostname: http://server-or-conatiner-hostname:8000    visibleFields: public_ip,region,country,city,location,organisation,postal_code,timezone

Info#

  • CORS: 🟠 Proxied
  • Auth: 🟢 Required
  • Price: 🟢 Free
  • Host: Self-Hosted (see Gluetun)
  • Privacy: See Gluetun Wiki

Drone CI Builds#

Display the last builds from a Drone CI instance. A self-hosted CI system that uses docker.

Options#

FieldTypeRequiredDescription
hoststringRequiredThe hostname of the Drone CI instance.
apiKeystringRequiredThe API key (https://[your-drone-instance]/account).
limitintegerOptionalLimit the amounts of listed builds.
repostringOptionalShow only builds of the specified repo

Example#

- type: drone-io  updateInterval: 30  options:    host: https://drone.somedomain.com    apiKey: my-very-secret-api-key    limit: 10

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Required
  • Price: 🟢 Free
  • Host: Self-Hosted (see Drone)
  • Privacy: See Drone

Linkding#

Linkding is a self-hosted bookmarking service, which has a clean interface and is simple to set up. This lists the links, filterable by tags.

Options#

FieldTypeRequiredDescription
hoststringRequiredThe hostname of the Drone CI instance.
apiKeystringRequiredThe API key (https://your-linkding-instance/settings/integrations).
tagslist of stringOptionalFilter the links by tag.

Example#

- type: linkding  updateInterval: 30  options:    host: https://lingding.somedomain.com    apiKey: my-very-secret-api-key    tags:       - rpg      - markdown

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Required
  • Price: 🟢 Free
  • Host: Self-Hosted (see Linkding)
  • Privacy: See Linkding

Uptime Kuma#

Uptime Kuma is an easy-to-use self-hosted monitoring tool.

Options#

FieldTypeRequiredDescription
urlstringRequiredThe URL of the Uptime Kuma instance
apiKeystringRequiredThe API key (see https://github.com/louislam/uptime-kuma/wiki/API-Keys).

Example#

- type: uptime-kuma  useProxy: true  options:    apiKey: uk2_99H0Yd3I2pPNIRfn0TqBFu4g5q85R1Mh75yZzw6H    url: http://192.168.1.106:3691/metrics

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟢 Required
  • Price: 🟢 Free
  • Host: Self-Hosted (see Uptime Kuma )
  • Privacy: See Uptime Kuma

System Resource Monitoring#

Glances#

The easiest method for displaying system info and resource usage in Dashy is with Glances.

Glances is a cross-platform monitoring tool developed by @nicolargo. It's similar to top/htop but with a Rest API and many data exporters available. Under the hood, it uses psutil for retrieving system info.

If you don't already have it installed, either follow the Installation Guide for your system, or setup with Docker, or use the one-line install script: curl -L https://bit.ly/glances | /bin/bash.

If you are using Docker to run glances make sure to add the enviroment variable -e TZ = {YourTimeZone}. You can get a list of valid timezones by running timedatectl list-timezones on any linux system. This is needed so the graphs show the currect time.

Here an example for Docker

 docker run -d \    --name glances \    --restart unless-stopped \    -v /var/run/docker.sock:/var/run/docker.sock:ro \    -p 61208:61208 \    --pid host \    --privileged \    -e GLANCES_OPT=-w \    -e PUID=1000 \    -e PGID=1000 \    -e TZ=Europe/Zurich \    nicolargo/glances:latest

Glances can be launched with the glances command. You'll need to run it in web server mode, using the -w option for the API to be reachable. If you don't plan on using the Web UI, then you can disable it using --disable-webui. See the command reference docs for more info.

If Glaces is running on a Windows system it is recommanded to add the following arguments --disable-plugin all --enable-plugin cpu,mem,diskio,ip,network,containers,quicklook,load,fs,alert -w This is due to Glances not being that stable on windows, so disabling all plugins that aren't used by Dashy widgets can save on ressources.

Options#

All Glance's based widgets require a hostname. All other parameters are optional.

FieldTypeRequiredDescription
hostnamestringRequiredThe URL or IP + port to your Glances instance (without a trailing slash)
usernamestringOptionalIf you have setup basic auth on Glances, specify username here (defaults to glances)
passwordstringOptionalIf you have setup basic auth on Glances, specify password here. Note: since this password is in plaintext, it is important not to reuse it anywhere else
apiVersionstringOptionalSpecify an API version, defaults to V 3. Note that support for older versions is limited
limitnumberOptionalFor widgets that show a time-series chart, optionally limit the number of data points returned. A higher number will show more historical results, but will take longer to load. A value between 300 - 800 is usually optimal

Note that if auth is configured, requests must be proxied with useProxy: true

Info#

  • CORS: 🟢 Enabled
  • Auth: 🟠 Optional
  • Price: 🟢 Free
  • Host: Self-Hosted (see GitHub - Nicolargo/Glances)
  • Privacy: ⚫ No Policy Available

Screenshot#

example-screenshot


Current CPU Usage#

Live-updating current CPU usage, as a combined average across all cores

Example#

- type: gl-current-cpu  options:    hostname: http://192.168.130.2:61208

Current CPU Usage Speedometer#

Speedometer styled version of the Current CPU Usage widget

Example#

- type: gl-cpu-speedometer  options:    hostname: http://192.168.130.2:61208

CPU Usage Per Core#

Live-updating CPU usage breakdown per core

Example#

- type: gl-current-cores  options:    hostname: http://192.168.130.2:61208

CPU Usage History#

Recent CPU usage history, across all cores, and displayed by user and system

Options#

FieldTypeRequiredDescription
limitnumberOptionalLimit the number of results returned, rendering more data points will take longer to load. Defaults to 100

Example#

- type: gl-cpu-history  options:    hostname: http://192.168.130.2:61208    limit: 60

Current Memory Usage#

Real-time memory usage gauge, with more info visible on click

Example#

- type: gl-current-mem  options:    hostname: http://192.168.130.2:61208

Current Memory Usage Speedometer#

Speedometer styled version of the Current Memory Usage widget

Example#

- type: gl-mem-speedometer  options:    hostname: http://192.168.130.2:61208

Memory Usage History#

Recent memory usage chart

Options#

FieldTypeRequiredDescription
limitnumberOptionalLimit the number of results returned, rendering more data points will take longer to load. Defaults to 100

Example#

- type: gl-mem-history  options:    hostname: http://localhost:61208    limit: 80

Disk Space#

List connected disks, showing free / used space and other info (file system, mount point and space available)

Example#

- type: gl-disk-space  options:    hostname: http://192.168.130.2:61208

Disk IO#

Shows real-time read and write speeds and operations per sec for each disk

Example#

- type: gl-disk-io  options:    hostname: http://192.168.130.2:61208

System Load#

Shows the number of processes waiting in the run-queue, averaged across all cores. Displays for past 5, 10 and 15 minutes

Example#

- type: gl-system-load  options:    hostname: http://192.168.130.2:61208

System Load History#

Shows recent historical system load, calculated from the number of processes waiting in the run-queue, in 1, 5 and 15 minute intervals, and averaged across all cores. Optionally specify limit to set number of results returned, defaults to 500, max 100000, but the higher the number the longer the load and render times will be.

Example#

- type: gl-load-history  options:    hostname: http://192.168.130.2:61208

Network Interfaces#

Lists visible network interfaces, including real-time upload/ download stats

Example#

- type: gl-network-interfaces  options:    hostname: http://192.168.130.2:61208

Network Traffic#

Shows amount of data recently uploaded/ downloaded across all network interfaces. Optionally set the limit option to specify number historical of data points to return

Example#

- type: gl-network-traffic  options:    hostname: http://192.168.130.2:61208    limit: 500

Resource Usage Alerts#

Lists recent high resource usage alerts (e.g. CPU, mem, IO, load, temp)

Example#

- type: gl-alerts  options:    hostname: http://192.168.130.2:61208

IP Address#

Shows public and private IP address. Note that the ip plugin is not available on all instances of Glances.

Example#

- type: gl-ip-address  options:    hostname: http://192.168.130.2:61208

CPU Temp#

Displays temperature data from system CPUs.

Note: This widget uses the sensors plugin, which is disabled by default, and may cause performance issues. +You'll need to enable the sensors plugin to use this widget, using: --enable-plugin sensors when you start Glances.

Options#

FieldTypeRequiredDescription
unitsstringOptionalUse C to display temperatures in Celsius or F to use Fahrenheit. Defaults to C.

Example#

- type: gl-cpu-temp  options:    hostname: http://192.168.130.2:61208    units: C

Dynamic Widgets#

Iframe Widget#

Embed any webpage into your dashboard as a widget.

Options#

FieldTypeRequiredDescription
urlstringRequiredThe URL to the webpage to embed
frameHeightnumberOptionalIf needed, specify height of iframe in px. E.g. 400, defaults to auto

Example#

- type: iframe  options:    url: https://fiatleak.com/

HTML Embedded Widget#

Many websites and apps provide their own embeddable widgets. These can be used with Dashy using the Embed widget, which lets you dynamically embed and HTML, CSS or JavaScript contents.

⚠️ NOTE: Use with extreme caution. Embedding a script from an untrustworthy source may have serious unintended consequences.

Options#

FieldTypeRequiredDescription
htmlstringOptionalHTML contents to render in the widget
scriptstringOptionalRaw JavaScript code to execute (caution)
scriptSrcstringOptionalA URL to JavaScript content (caution)
cssstringOptionalAny stylings for widget contents

Example#

- type: embed  options:    scriptSrc: https://cdn.speedcheck.org/basic/scbjs.min.js    html: |      <div id="sc-container">      <div id="sc-branding" class="sc-bb">      <a target="_blank" href="https://www.speedcheck.org/">      <img src="https://cdn.speedcheck.org/branding/speedcheck-logo-18.png" alt="Speedcheck"/>      </a>      </div>      </div>

Or

- type: embed    options:      css: '.coinmarketcap-currency-widget { color: var(--widget-text-color); }'      html: '<div class="coinmarketcap-currency-widget" data-currencyid="1" data-base="USD" data-secondary="" data-ticker="true" data-rank="true" data-marketcap="true" data-volume="true" data-statsticker="true" data-stats="USD"></div>'      scriptSrc: 'https://files.coinmarketcap.com/static/widget/currency.js'

You can also use this widget to display an image, wither locally or from a remote origin.

- type: embed  options:    html: '<img src="https://dashy.lan/item-icons/my-image.png" />'

API Response#

Directly output plain-text response from any API-enabled service.

// Coming soon...


Prometheus Data#

Display data from any service with a Prometheus exporter.

// Coming soon...


Data Feed#

Show live data from an RSS-enabled service. The only required parameter is rssUrl, which is the URL to the ATOM feed. See RSS Widget for full list of available options.

Example#

- type: rss-feed  options:    rssUrl: https://notes.aliciasykes.com/feed

Usage & Customizations#

Widget Usage Guide#

Like items, widgets are placed under sections. You may have one or more widgets per section.

In your YAML config file, this will look something like:

sections:- name: Today  icon: far fa-calendar-day  widgets:  - type: clock    options:      format: en-GB  - type: weather    options:      apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      city: London      units: metric

In this example, there is a single section, named "Today", using a Calendar icon from Font-Awesome. It has 2 widgets, a clock and the current weather.


Continuous Updates#

By default, a widget which displays dynamic data from an external source, will only fetch results on page load. If you would like to keep data updated at all times, you can enable Continuous Updates. This is done by setting a time value in the updateInterval field.

The value of updateInterval is optional, and is specified and seconds. It must be more than 10 and less than 7200.

For example, the following widget displaying stats from Pi-Hole will update ever 20 seconds.

widgets:- type: pi-hole-stats  updateInterval: 20  options:    hostname: http://192.168.130.2

Note that if you have many widgets, and set them to continuously update frequently, you will notice a hit to performance. A widget that relies on data from an external API, will also consume your usage quota faster, if set to keep updating.


Proxying Requests#

If a widget fails to make a data request, and the console shows a CORS error, this means the server is blocking client-side requests.

Dashy has a built-in CORS proxy (services/cors-proxy.js), which will be used automatically by some widgets, or can be forced to use by other by setting the useProxy option.

For example:

widgets:- type: pi-hole-stats  useProxy: true  options:    hostname: http://pi-hole.local

Alternatively, and more securely, you can set the auth headers on your service to accept requests from Dashy. For example:

Access-Control-Allow-Origin: https://location-of-dashy/Vary: Origin

Setting Timeout#

If the endpoint you are requesting data from is slow to respond, you may see a timeout error in the console. This can easily be fixed by specifying the timeout property on the offending widget. This should be an integer value, in milliseconds. By default timeout is 2500 ms (2½ seconds).

For example:

- type: gl-current-cpu  timeout: 8000  options:    hostname: https://glances.dns-device.local

Adding Labels#

If you have multiple widgets of the same type in a single section, it may not be clear what each one is. To overcome this, you can add a custom label to any given widget, using the label property.

For example:

- name: CPU Usage  icon: fas fa-tachometer  widgets:  - type: gl-current-cpu    label: Meida Server    options:      hostname: http://media-server.lan:61208  - type: gl-current-cpu    label: Firewall    options:      hostname: http://firewall.lan:61208  - type: gl-current-cpu    label: File Sync Server    options:      hostname: http://file-sync.lan:61208

Ignoring Errors#

When there's an error fetching or displaying a widgets data, then it will be highlighted in yellow, and a message displayed on the UI.

In some instances, this is a false positive, and the widget is actually functioning correctly. If this is the case, you can disable the UI error message of a given widget by setting: ignoreErrors: true

- type: gl-disk-io  ignoreErrors: true  options:    hostname: https://glances.dns-device.local

Widget Styling#

Like elsewhere in Dashy, all colours can be easily modified with CSS variables.

Widgets use the following color variables, which can be overridden if desired:

  • --widget-text-color - Text color, defaults to --primary
  • --widget-background-color - Background color, defaults to --background-darker
  • --widget-accent-color - Accent color, defaults to --background

For more info on how to apply custom variables, see the Theming Docs


Customizing Charts#

For widgets that contain charts, you can set an array of colors under chartColors. To specify the chart height, set chartHeight to an integer (in px), defaults to 300. For example:

- type: gl-load-history  options:    hostname: http://192.168.130.2:61208    chartColors: ['#9b5de5', '#f15bb5', '#00bbf9', '#00f5d4']    chartHeight: 450

Language Translations#

Since most of the content displayed within widgets is fetched from an external API, unless that API supports multiple languages, translating dynamic content is not possible.

However, any hard-coded content is translatable, and all dates and times will display in your local format.

For more info about multi-language support, see the Internationalization Docs.


Widget UI Options#

Widgets can be opened in full-page view, by clicking the Arrow icon (top-right). The URL in your address bar will also update, and visiting that web address directly will take you straight to that widget.

You can reload the data of any widget, by clicking the Refresh Data icon (also in top-right). This will only affect the widget where the action was triggered from.

All config options that can be applied to sections, can also be applied to widget sections. For example, to make a widget section double the width, set displayData.cols: 2 within the parent section. You can collapse a widget (by clicking the section title), and collapse state will be saved locally.

Widgets cannot currently be edited through the UI. This feature is in development, and will be released soon. In the meantime, you can either use the JSON config editor, or use VS Code Server, or just SSH into your box and edit the conf.yml file directly.


Build your own Widget#

Widgets are built in a modular fashion, making it easy for anyone to create their own custom components.

For a full tutorial on creating your own widget, you can follow this guide, or take a look at here for a code example.

Alternatively, for displaying simple data, you could also just use the either the iframe, embed, data feed or API response widgets.


Requesting a Widget#

Suggestions for widget ideas are welcome. But there is no guarantee that I will build your widget idea.

Please only request widgets for services that:

  • Have a publicly accessible API
  • Are CORS and HTTPS enabled
  • Are free to use, or have a free plan
  • Allow for use in their Terms of Service
  • Would be useful for other users

You can suggest a widget here, please star the repo before submitting a ticket. If you are a monthly GitHub sponsor, I will happily build out a custom widget for any service that meets the above criteria, usually within 2 weeks of initial request.

For services that are not officially supported, it is likely still possible to display data using either the iframe, embed or API response widgets. For more advanced features, like charts and action buttons, you could also build your own widget, using this tutorial, it's fairly straight forward, and you can use an existing widget (or this example) as a template.


Troubleshooting Widget Errors#

If an error occurs when fetching or rendering results, you will see a short message in the UI. If that message doesn't adequately explain the problem, then you can open the browser console to see more details.

Before proceeding, ensure that if the widget requires auth your API is correct, and for custom widgets, double check that the URL and protocol is correct.

If you're able to, you can find more information about why the request may be failing in the Dev Tools under the Network tab, and you can ensure your endpoint is correct and working using a tool like Postman.

CORS Errors#

The most common issue is a CORS error. This is a browser security mechanism which prevents the client-side app (Dashy) from from accessing resources on a remote origin, without that server's explicit permission (e.g. with headers like Access-Control-Allow-Origin). See the MDN Docs for more info: Cross-Origin Resource Sharing.

There are several ways to fix a CORS error:

Option 1 - Ensure Correct Protocol#

You will get a CORS error if you try and access a http service from a https source. So ensure that the URL you are requesting has the right protocol, and is correctly formatted.

Option 2 - Set Headers#

If you have control over the destination (e.g. for a self-hosted service), then you can simply apply the correct headers. -Add the Access-Control-Allow-Origin header, with the value of either * to allow requests from anywhere, or more securely, the host of where Dashy is served from. For example:

Access-Control-Allow-Origin: https://url-of-dashy.local

or

Access-Control-Allow-Origin: *

Option 3 - Proxying Request#

You can route requests through Dashy's built-in CORS proxy. Instructions and more details can be found here. If you don't have control over the target origin, and you are running Dashy either through Docker, with the Node server or on Netlify, then this solution will work for you.

Just add the useProxy: true option to the failing widget.

Option 4 - Use a plugin#

For testing purposes, you can use an addon, which will disable the CORS checks. You can get the Allow-CORS extension for Chrome or Firefox, more details here


Raising an Issue#

If you need to submit a bug report for a failing widget, then please include the full console output (see how) as well as the relevant parts of your config file. Before sending the request, ensure you've read the docs. If you're new to GitHub, an haven't previously contributed to the project, then please fist star the repo to avoid your ticket being closed by the anti-spam bot.

- +Add the Access-Control-Allow-Origin header, with the value of either * to allow requests from anywhere, or more securely, the host of where Dashy is served from. For example:

Access-Control-Allow-Origin: https://url-of-dashy.local

or

Access-Control-Allow-Origin: *

Option 3 - Proxying Request#

You can route requests through Dashy's built-in CORS proxy. Instructions and more details can be found here. If you don't have control over the target origin, and you are running Dashy either through Docker, with the Node server or on Netlify, then this solution will work for you.

Just add the useProxy: true option to the failing widget.

Option 4 - Use a plugin#

For testing purposes, you can use an addon, which will disable the CORS checks. You can get the Allow-CORS extension for Chrome or Firefox, more details here


Raising an Issue#

If you need to submit a bug report for a failing widget, then please include the full console output (see how) as well as the relevant parts of your config file. Before sending the request, ensure you've read the docs. If you're new to GitHub, an haven't previously contributed to the project, then please fist star the repo to avoid your ticket being closed by the anti-spam bot.

+ \ No newline at end of file diff --git a/index.html b/index.html index ea6e2769..c1445129 100644 --- a/index.html +++ b/index.html @@ -6,13 +6,13 @@ Dashy | Dashy - +

Dashy

The Ultimate Homepage for your Homelab

Dashy is an open source, highly customizable, easy to use, privacy-respecting dashboard app.Keep Reading...
Feature List

Theming

With tons of built-in themes to choose form, plus a UI color palette editor, you can have a unique looking dashboard in no time. There is also support for custom CSS, and since all properties use CSS variables, it is easy to override.
Learn more in the Docs Docs

Icons

Dashy can auto-fetch icons from the favicon of each of your apps/ services. There is also native support for Font Awesome, Material Design Icons, emoji icons and of course normal images.
Learn more in the Docs Docs
Screenshot Coming Soon

Status Indicators

Get an instant overview of the health of each of your apps with status indicators. Once enabled, a small dot next to each app will show weather it is up and online, with more info like response time visible on hover.
Learn more in the Docs Docs

Authentication

Need to protect your dashboard, the simple auth feature is super quick to enable, and has support for multiple users with granular controls. Dashy also has built-in support for Keycloak and other SSO providers.
Learn more in the Docs Docs
Screenshot Coming Soon

Widgets

Display dynamic content from any API-enabled service. Dashy comes bundled with 50+ pre-built widgets for self-hosted services, productivity and monitoring.
Learn more in the Docs Docs

Alternate Views

As well as the default home, there is also a minimal view, which makes a great fast-loading browser startpage. Plus a workspace view useful for working on multiple apps at once, all without having to leave your dashboard.
Learn more in the Docs Docs

Launching Methods

Choose how to launch each of your apps by default, or right click for all options. Apps can be opened in a new tab, the same tab, a quick pop-up modal or in the workspace view.
Learn more in the Docs Docs
Screenshot Coming Soon

Search & Shortcuts

To search, just start typing, results will be filtered instantly. Use the arrow keys or tab to navigate through results, and press enter to launch. You can also create custom shortcuts for frequently used apps, or add custom tags for easier searching. Dashy can also be used to search the web using your favorite search engine.
Learn more in the Docs Docs

Cloud Backup & Sync

There is an optional, end-to-end encrypted, free backup cloud service. This enables you to have your config backed up off-site, and to sync data between multiple instances easily.
Learn more in the Docs Docs
Screenshot Coming Soon

Configuration

Dashy's config is specified in a simple YAML file. But you can also configure the directly through the UI, and have changes written to, and backed up on disk. Real-time validation and hints are in place to help you.
Learn more in the Docs Docs

Multi-Language Support

Dashy's UI has been translated into several languages by several amazing contributors. Currently English, German, French, Dutch and Slovenian are supported. Your language should be applied automatically, or you can change it in the config menu.
Learn more in the Docs Docs
Screenshot Coming Soon

Easy Deployment

Although Dashy can be easily run on bare metal, the quickest method of getting started is with Docker. Just run `docker run -p 8080:80 lissy93/dashy` to pull, build and and run Dashy.
Learn more in the Docs Docs
Screenshot Coming Soon

Customizable Layouts

Structure your dashboard to fit your use case. From the UI, you can choose between different layouts, item sizes, show/ hide components, switch themes plus more. You can customize pretty much every area of your dashboard. There are config options for custom header, footer, nav bar links, title etc. You can also choose to hide any elements you don't need.
Learn more in the Docs Docs
Screenshot Coming Soon
- + \ No newline at end of file diff --git a/markdown-page/index.html b/markdown-page/index.html index d9d4d5fb..5b1ac4d3 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -6,13 +6,13 @@ Markdown page example | Dashy - + - + \ No newline at end of file diff --git a/search/index.html b/search/index.html index 7803b567..61b73e50 100644 --- a/search/index.html +++ b/search/index.html @@ -6,13 +6,13 @@ Search the documentation | Dashy - + - + \ No newline at end of file diff --git a/survey/index.html b/survey/index.html index 7c00dfec..841a82c5 100644 --- a/survey/index.html +++ b/survey/index.html @@ -6,13 +6,13 @@ Dashy Survey | Dashy - + - + \ No newline at end of file