docs/assets/js/99581c43.b0751f07.js
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([[413],{2888:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>n,metadata:()=>d,toc:()=>r});var s=i(4848),o=i(8453);const n={title:"Custom Widgets"},l=void 0,d={id:"guides/custom-widgets",title:"Custom Widgets",description:"COSMOS allows you to build custom widgets which can be deployed with your plugin and used in Telemetry Viewer. Building custom widgets can utilize any javascript frameworks but since COSMOS is written with Vue.js, we will use that framework in this tutorial. Please see the Widget Generator guide for information about generating the scaffolding for a custom widget.",source:"@site/docs/guides/custom-widgets.md",sourceDirName:"guides",slug:"/guides/custom-widgets",permalink:"/docs/guides/custom-widgets",draft:!1,unlisted:!1,editUrl:"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/guides/custom-widgets.md",tags:[],version:"current",frontMatter:{title:"Custom Widgets"},sidebar:"defaultSidebar",previous:{title:"COSMOS and NASA cFS",permalink:"/docs/guides/cfs"},next:{title:"Little Endian Bitfields",permalink:"/docs/guides/little-endian-bitfields"}},c={},r=[{value:"Custom Widgets",id:"custom-widgets",level:2},{value:"Helloworld Widget",id:"helloworld-widget",level:3}];function a(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",img:"img",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(t.p,{children:["COSMOS allows you to build custom widgets which can be deployed with your ",(0,s.jsx)(t.a,{href:"/docs/configuration/plugins",children:"plugin"})," and used in ",(0,s.jsx)(t.a,{href:"/docs/tools/tlm-viewer",children:"Telemetry Viewer"}),". Building custom widgets can utilize any javascript frameworks but since COSMOS is written with Vue.js, we will use that framework in this tutorial. Please see the ",(0,s.jsx)(t.a,{href:"../getting-started/generators#widget-generator",children:"Widget Generator"})," guide for information about generating the scaffolding for a custom widget."]}),"\n",(0,s.jsx)(t.h2,{id:"custom-widgets",children:"Custom Widgets"}),"\n",(0,s.jsxs)(t.p,{children:["We're basically going to follow the COSMOS ",(0,s.jsx)(t.a,{href:"https://github.com/OpenC3/cosmos/tree/main/openc3-cosmos-init/plugins/packages/openc3-cosmos-demo",children:"Demo"})," and explain how that custom widget was created."]}),"\n",(0,s.jsxs)(t.p,{children:["If you look at the bottom of the Demo's ",(0,s.jsx)(t.a,{href:"https://github.com/OpenC3/cosmos/blob/main/openc3-cosmos-init/plugins/packages/openc3-cosmos-demo/plugin.txt",children:"plugin.txt"})," file you'll see we declare the widgets:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-ruby",children:"WIDGET BIG\nWIDGET HELLOWORLD\n"})}),"\n",(0,s.jsxs)(t.p,{children:["When the plugin is deployed this causes COSMOS to look for the as-built widgets. For the BIG widget it will look for the widget at ",(0,s.jsx)(t.code,{children:"tools/widgets/BigWidget/BigWidget.umd.min.js"}),". Similarly it looks for HELLOWORLD at ",(0,s.jsx)(t.code,{children:"tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js"}),". These directories and file names may seem mysterious but it's all about how the widgets get built."]}),"\n",(0,s.jsx)(t.h3,{id:"helloworld-widget",children:"Helloworld Widget"}),"\n",(0,s.jsxs)(t.p,{children:["The Helloworld Widget source code is found in the plugin's src directory and is called ",(0,s.jsx)(t.a,{href:"https://github.com/OpenC3/cosmos/blob/main/openc3-cosmos-init/plugins/packages/openc3-cosmos-demo/src/HelloworldWidget.vue",children:"HelloworldWidget.vue"}),". The basic structure is as follows:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-vue",children:'<template>\n \x3c!-- Implement widget here --\x3e\n</template>\n\n<script>\nimport Widget from "@openc3/tool-common/src/components/widgets/Widget";\nexport default {\n mixins: [Widget],\n data() {\n return {\n // Reactive data items\n };\n },\n};\n<\/script>\n<style scoped>\n/* widget specific style */\n</style>\n'})}),"\n",(0,s.jsx)(t.admonition,{title:"Vue & Vuetify",type:"info",children:(0,s.jsxs)(t.p,{children:["For more information about how the COSMOS frontend is built (including all the Widgets) please check out ",(0,s.jsx)(t.a,{href:"https://vuejs.org",children:"Vue.js"})," and ",(0,s.jsx)(t.a,{href:"https://vuetifyjs.com",children:"Vuetify"}),"."]})}),"\n",(0,s.jsxs)(t.p,{children:["To build this custom widget we changed the Demo ",(0,s.jsx)(t.a,{href:"https://github.com/OpenC3/cosmos/blob/main/openc3-cosmos-init/plugins/packages/openc3-cosmos-demo/Rakefile",children:"Rakefile"})," to call ",(0,s.jsx)(t.code,{children:"yarn run build"})," when the plugin is built. ",(0,s.jsx)(t.code,{children:"yarn run XXX"})," looks for 'scripts' to run in the ",(0,s.jsx)(t.a,{href:"https://github.com/OpenC3/cosmos/blob/main/openc3-cosmos-init/plugins/packages/openc3-cosmos-demo/package.json",children:"package.json"})," file. If we open package.json we find the following:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-json",children:' "scripts": {\n "build": "vue-cli-service build --target lib --dest tools/widgets/HelloworldWidget --formats umd-min src/HelloworldWidget.vue --name HelloworldWidget && vue-cli-service build --target lib --dest tools/widgets/BigWidget --formats umd-min src/BigWidget.vue --name BigWidget"\n },\n'})}),"\n",(0,s.jsxs)(t.p,{children:["This uses the ",(0,s.jsx)(t.code,{children:"vue-cli-service"})," to build the code found at ",(0,s.jsx)(t.code,{children:"src/HelloworldWidget.vue"})," and formats as ",(0,s.jsx)(t.code,{children:"umd-min"})," and puts it in the ",(0,s.jsx)(t.code,{children:"tools/widgets/HelloworldWidget"})," directory. So this is why the plugin looks for the plugin at ",(0,s.jsx)(t.code,{children:"tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js"}),". Click ",(0,s.jsx)(t.a,{href:"https://cli.vuejs.org/guide/cli-service.html#vue-cli-service-build",children:"here"})," for the ",(0,s.jsx)(t.code,{children:"vue-cli-service build"})," documentation."]}),"\n",(0,s.jsxs)(t.p,{children:["If you look at the Demo plugin's ",(0,s.jsx)(t.a,{href:"https://github.com/OpenC3/cosmos/blob/main/openc3-cosmos-init/plugins/packages/openc3-cosmos-demo/targets/INST/screens/simple.txt",children:"simple.txt"})," screen you'll see we're using the widgets:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-ruby",children:"SCREEN AUTO AUTO 0.5\nLABELVALUE <%= target_name %> HEALTH_STATUS CCSDSSEQCNT\nHELLOWORLD\nBIG <%= target_name %> HEALTH_STATUS TEMP1\n"})}),"\n",(0,s.jsx)(t.p,{children:"Opening this screen in Telemetry Viewer results in the following:"}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"Simple Screen",src:i(4270).A+"",width:"681",height:"210"})}),"\n",(0,s.jsx)(t.p,{children:"While this is a simple example the possibilities with custom widgets are limitless!"})]})}function u(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},4270:(e,t,i)=>{i.d(t,{A:()=>s});const s=i.p+"assets/images/simple_screen-e3de1ad836c0661d73a0ba970f991c64df8ecc7e23f9e944b6508a9a43fbc33c.png"},8453:(e,t,i)=>{i.d(t,{R:()=>l,x:()=>d});var s=i(6540);const o={},n=s.createContext(o);function l(e){const t=s.useContext(n);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:l(e.components),s.createElement(n.Provider,{value:t},e.children)}}}]);