@rainbow-robotics/muscat-plugin-kit 1.10.1-dev.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +282 -282
- package/cli/README.md +274 -274
- package/cli/bin/create-muscat-plugin.mjs +8 -8
- package/cli/bin/muscat-pk.mjs +155 -155
- package/cli/bundle-templates.mjs +31 -31
- package/cli/docker/Dockerfile.cpp +28 -28
- package/cli/docker/Dockerfile.dev +30 -30
- package/cli/docker/Dockerfile.python +21 -21
- package/cli/m5-e2e.mjs +69 -69
- package/cli/prepack.mjs +10 -10
- package/cli/src/ai-rules.mjs +70 -70
- package/cli/src/build.mjs +447 -447
- package/cli/src/check-package.mjs +13 -13
- package/cli/src/completion.mjs +166 -166
- package/cli/src/cpp.mjs +78 -78
- package/cli/src/cppIde.mjs +75 -75
- package/cli/src/dev.mjs +165 -165
- package/cli/src/devBack.mjs +734 -727
- package/cli/src/devUi.mjs +247 -243
- package/cli/src/esbuild.mjs +56 -56
- package/cli/src/host_agent.py +223 -223
- package/cli/src/manifest.mjs +287 -287
- package/cli/src/mcp.mjs +1071 -1071
- package/cli/src/muscatLocal.mjs +209 -209
- package/cli/src/new.mjs +343 -343
- package/cli/src/pluginDevServer.mjs +111 -111
- package/cli/src/ports.mjs +193 -193
- package/cli/src/python.mjs +112 -112
- package/cli/src/ros2.mjs +109 -109
- package/cli/src/sdk.mjs +117 -117
- package/cli/src/storybook.mjs +168 -168
- package/cli/src/type.mjs +141 -141
- package/cli/src/uninstall.mjs +81 -81
- package/cli/src/update.mjs +295 -295
- package/cli/src/util.mjs +441 -441
- package/cli/src/zenohDev.mjs +83 -81
- package/cli/storybook-dist/_design-tokens.css +4957 -4957
- package/cli/storybook-dist/_stories-src/NxAvatar.stories.tsx +27 -27
- package/cli/storybook-dist/_stories-src/NxPagination.stories.tsx +28 -28
- package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordion.stories.tsx +46 -46
- package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordionGroup.stories.tsx +73 -73
- package/cli/storybook-dist/_stories-src/RBBadge/RBBadge.stories.tsx +93 -93
- package/cli/storybook-dist/_stories-src/RBBattery/RBBattery.stories.tsx +74 -74
- package/cli/storybook-dist/_stories-src/RBButton/RBCheckIconButton.stories.tsx +28 -28
- package/cli/storybook-dist/_stories-src/RBButton/RBCheckLabelButton.stories.tsx +84 -84
- package/cli/storybook-dist/_stories-src/RBButton/RBIconButton.stories.tsx +57 -57
- package/cli/storybook-dist/_stories-src/RBButton/RBInlineLabelButton.stories.tsx +41 -41
- package/cli/storybook-dist/_stories-src/RBButton/RBLabelButton.stories.tsx +60 -60
- package/cli/storybook-dist/_stories-src/RBDatePicker/RBDateInput.stories.tsx +44 -44
- package/cli/storybook-dist/_stories-src/RBDatePicker/RBRangeDateInput.stories.tsx +56 -56
- package/cli/storybook-dist/_stories-src/RBDialog/RBAlert.stories.tsx +51 -51
- package/cli/storybook-dist/_stories-src/RBDialog/RBConfirm.stories.tsx +55 -55
- package/cli/storybook-dist/_stories-src/RBDialog/RBPrompt.stories.tsx +52 -52
- package/cli/storybook-dist/_stories-src/RBDivider/RBDivider.stories.tsx +93 -93
- package/cli/storybook-dist/_stories-src/RBEmptyView/RBEmptyView.stories.tsx +49 -49
- package/cli/storybook-dist/_stories-src/RBIcons/RBColorIcons.stories.tsx +108 -108
- package/cli/storybook-dist/_stories-src/RBIcons/RBIcons.stories.tsx +106 -106
- package/cli/storybook-dist/_stories-src/RBInput/RBCheckBox.stories.tsx +89 -89
- package/cli/storybook-dist/_stories-src/RBInput/RBMultiRangeInput.stories.tsx +64 -64
- package/cli/storybook-dist/_stories-src/RBInput/RBRadioBox.stories.tsx +65 -65
- package/cli/storybook-dist/_stories-src/RBInput/RBRadioButton.stories.tsx +68 -68
- package/cli/storybook-dist/_stories-src/RBInput/RBSelectBox.stories.tsx +216 -216
- package/cli/storybook-dist/_stories-src/RBInput/RBSideNumberInput.stories.tsx +90 -90
- package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextArea.stories.tsx +45 -45
- package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextInput.stories.tsx +50 -50
- package/cli/storybook-dist/_stories-src/RBInput/RBTextField.stories.tsx +102 -102
- package/cli/storybook-dist/_stories-src/RBJoyStick/RBJoyStick.stories.tsx +31 -31
- package/cli/storybook-dist/_stories-src/RBLight/RBLight.stories.tsx +36 -36
- package/cli/storybook-dist/_stories-src/RBPagination/RBPagination.stories.tsx +49 -49
- package/cli/storybook-dist/_stories-src/RBShadcn/RBCard/RBCard.stories.tsx +89 -89
- package/cli/storybook-dist/_stories-src/RBShadcn/RBCommand/RBCommand.stories.tsx +116 -116
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDialog/RBDialog.stories.tsx +74 -74
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDrawer/RBDrawer.stories.tsx +99 -99
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDropdownMenu/RBDropdownMenu.stories.tsx +123 -123
- package/cli/storybook-dist/_stories-src/RBShadcn/RBMenubar/RBMenubar.stories.tsx +135 -135
- package/cli/storybook-dist/_stories-src/RBShadcn/RBPopover/RBPopover.stories.tsx +69 -69
- package/cli/storybook-dist/_stories-src/RBShadcn/RBResizable/RBResizable.stories.tsx +49 -49
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSheet/RBSheet.stories.tsx +91 -91
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSlider/RBSlider.stories.tsx +38 -38
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSwitch/RBSwitch.stories.tsx +112 -112
- package/cli/storybook-dist/_stories-src/RBShadcn/RBTabs/RBTabs.stories.tsx +75 -75
- package/cli/storybook-dist/_stories-src/RBShadcn/RBToggle/RBToggle.stories.tsx +51 -51
- package/cli/storybook-dist/_stories-src/RBShadcn/RBToggleGroup/RBToggleGroup.stories.tsx +84 -84
- package/cli/storybook-dist/_stories-src/RBTab/RBChipTab.stories.tsx +102 -102
- package/cli/storybook-dist/_stories-src/RBTab/RBChipsBoxTab.stories.tsx +78 -78
- package/cli/storybook-dist/_stories-src/RBTab/RBTab.stories.tsx +57 -57
- package/cli/storybook-dist/_stories-src/RBTable/RBTable.stories.tsx +177 -177
- package/cli/storybook-dist/_stories-src/RBTable/RBTableRow.stories.tsx +64 -64
- package/cli/storybook-dist/_stories-src/RBToast/RBToast.stories.tsx +117 -117
- package/cli/storybook-dist/_stories-src/RBTooltip/RBTooltip.stories.tsx +50 -50
- package/cli/storybook-dist/_stories-src/loading/RBSpinner.stories.tsx +30 -30
- package/cli/storybook-dist/_stories-src/nx-button/NxButton.stories.tsx +54 -54
- package/cli/storybook-dist/_stories-src/nx-button/NxPointerHoldButton.stories.tsx +57 -57
- package/cli/storybook-dist/_stories-src/nx-icons/NxIcons.stories.tsx +48 -48
- package/cli/storybook-dist/_stories-src/nx-inputs/NxNumberInput.stories.tsx +103 -103
- package/cli/storybook-dist/_stories-src/nx-inputs/NxRangeInput.stories.tsx +27 -27
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSelectBox.stories.tsx +67 -67
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSlideRange.stories.tsx +45 -45
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSwitch.stories.tsx +27 -27
- package/cli/storybook-dist/_stories-src/nx-inputs/NxTextArea.stories.tsx +48 -48
- package/cli/storybook-dist/_stories-src/nx-inputs/NxTextInput.stories.tsx +46 -46
- package/cli/storybook-dist/assets/{Color-YHDXOIA2-D6JqZzDJ.js → Color-YHDXOIA2-B4IER17l.js} +1 -1
- package/cli/storybook-dist/assets/{Docs-ESb7JAHg.js → Docs-C8GCHFtK.js} +3 -3
- package/cli/storybook-dist/assets/{Docs-6gD2kUo1.js → Docs-CgdEMPQP.js} +2 -2
- package/cli/storybook-dist/assets/{Docs-B9wd8Ok7.js → Docs-Ck3WHvk6.js} +3 -3
- package/cli/storybook-dist/assets/{Docs-CgFbWWXM.js → Docs-D9NHsoeZ.js} +2 -2
- package/cli/storybook-dist/assets/{Docs-DBQup8Bu.js → Docs-DNYQC7nl.js} +3 -3
- package/cli/storybook-dist/assets/{Docs-CMjovnSY.js → Docs-DUfeiM4I.js} +4 -4
- package/cli/storybook-dist/assets/{DocsRenderer-CFRXHY34-BOUI1AHi.js → DocsRenderer-CFRXHY34-C0WhyDoR.js} +1 -1
- package/cli/storybook-dist/assets/{NxAvatar.stories-DsYFMUh3.js → NxAvatar.stories-CwnK8AUF.js} +1 -1
- package/cli/storybook-dist/assets/{NxButton.stories-CHfNcqsc.js → NxButton.stories-ueYdosfQ.js} +8 -8
- package/cli/storybook-dist/assets/{NxNumberInput.stories-BFw_4vFE.js → NxNumberInput.stories-M5ZCLbrK.js} +1 -1
- package/cli/storybook-dist/assets/{NxPagination.stories-DVfxyw4M.js → NxPagination.stories-bxxUnHEL.js} +1 -1
- package/cli/storybook-dist/assets/{NxPointerHoldButton.stories-BzyxUWoZ.js → NxPointerHoldButton.stories-BHxB2kr5.js} +1 -1
- package/cli/storybook-dist/assets/{NxRangeInput.stories-DmRdzBc1.js → NxRangeInput.stories-BKfr-fp4.js} +6 -6
- package/cli/storybook-dist/assets/{NxSelectBox.stories-B1KkNUOf.js → NxSelectBox.stories-CG8FuTBq.js} +1 -1
- package/cli/storybook-dist/assets/{NxSlideRange.stories-CyOdvfQ6.js → NxSlideRange.stories-BRTFtMTL.js} +1 -1
- package/cli/storybook-dist/assets/{NxSwitch.stories-DrDBw0qp.js → NxSwitch.stories-Bwuyzn-R.js} +1 -1
- package/cli/storybook-dist/assets/{NxTextArea.stories-DTB2aqNS.js → NxTextArea.stories-COq2sGqu.js} +1 -1
- package/cli/storybook-dist/assets/{NxTextInput.stories-DU0rucmM.js → NxTextInput.stories-CjsBLz05.js} +1 -1
- package/cli/storybook-dist/assets/{RBAccordion.stories-DTfOtXtp.js → RBAccordion.stories-BARwuZ0Q.js} +3 -3
- package/cli/storybook-dist/assets/{RBAccordionGroup.stories-9y9BjrUe.js → RBAccordionGroup.stories-COrPxETW.js} +10 -10
- package/cli/storybook-dist/assets/{RBAlert.stories-DLTAv9fT.js → RBAlert.stories-BQrkjZPt.js} +3 -3
- package/cli/storybook-dist/assets/{RBBadge.stories-BNMACewA.js → RBBadge.stories-BTsLL-lK.js} +1 -1
- package/cli/storybook-dist/assets/{RBBattery.stories-B3kXMAt5.js → RBBattery.stories-DAeQdJbc.js} +1 -1
- package/cli/storybook-dist/assets/{RBCard.stories-Y-s8R2n7.js → RBCard.stories-HyhOE80R.js} +39 -39
- package/cli/storybook-dist/assets/{RBCheckBox.stories-DBuT9tL4.js → RBCheckBox.stories-KFk0WqX_.js} +1 -1
- package/cli/storybook-dist/assets/{RBCheckIconButton.stories-CWu1TL56.js → RBCheckIconButton.stories-CXbbktF5.js} +1 -1
- package/cli/storybook-dist/assets/{RBCheckLabelButton.stories-sCu2MGCX.js → RBCheckLabelButton.stories-DWfYz_9Z.js} +17 -17
- package/cli/storybook-dist/assets/{RBChipTab.stories-BX9qLJkR.js → RBChipTab.stories-JPEgVFAS.js} +5 -5
- package/cli/storybook-dist/assets/{RBChipsBoxTab.stories-35u1aJ-P.js → RBChipsBoxTab.stories-CTPuWXrQ.js} +1 -1
- package/cli/storybook-dist/assets/{RBColorIcons.stories-DAOZ5Ies.js → RBColorIcons.stories-DiFRZ5jk.js} +1 -1
- package/cli/storybook-dist/assets/RBCommand.stories-Pf1HAVIR.js +73 -0
- package/cli/storybook-dist/assets/{RBConfirm.stories-iMXcUh7Z.js → RBConfirm.stories-D1cEPUXk.js} +3 -3
- package/cli/storybook-dist/assets/{RBDateInput.stories-hK5rXECf.js → RBDateInput.stories-RPYpCjig.js} +1 -1
- package/cli/storybook-dist/assets/RBDialog.stories-DJH-0XSR.js +38 -0
- package/cli/storybook-dist/assets/{RBDivider.stories-BAK-iZ1Z.js → RBDivider.stories-uEj1vOgK.js} +1 -1
- package/cli/storybook-dist/assets/{RBDrawer.stories-B2nqf2Nh.js → RBDrawer.stories-BiMzElb2.js} +12 -12
- package/cli/storybook-dist/assets/RBDropdownMenu.stories-Da_TBkla.js +86 -0
- package/cli/storybook-dist/assets/{RBEmptyView.stories-nCenrgBh.js → RBEmptyView.stories-BHeKGfPS.js} +1 -1
- package/cli/storybook-dist/assets/{RBIconButton.stories-DRH7O3sp.js → RBIconButton.stories-NEsRFoYp.js} +1 -1
- package/cli/storybook-dist/assets/{RBIcons.stories-D3PyJXG8.js → RBIcons.stories-CcZ-TTLS.js} +1 -1
- package/cli/storybook-dist/assets/{RBInlineLabelButton.stories-modQbt10.js → RBInlineLabelButton.stories-B0wpdQyR.js} +1 -1
- package/cli/storybook-dist/assets/{RBJoyStick.stories-BY14qVgR.js → RBJoyStick.stories-DEgBou3K.js} +1 -1
- package/cli/storybook-dist/assets/{RBLabelButton.stories-DzF7vGwm.js → RBLabelButton.stories-DT8drIsF.js} +1 -1
- package/cli/storybook-dist/assets/{RBLight.stories-lF4FRmVh.js → RBLight.stories-Dh-aoeyG.js} +1 -1
- package/cli/storybook-dist/assets/{RBMenubar.stories-XhrI7bsV.js → RBMenubar.stories-D-H7UqVh.js} +1 -1
- package/cli/storybook-dist/assets/{RBMultiRangeInput.stories-DprllQDl.js → RBMultiRangeInput.stories-hlclv6jI.js} +1 -1
- package/cli/storybook-dist/assets/{RBPagination.stories-2v2gBJfC.js → RBPagination.stories-DWCeoZ_S.js} +1 -1
- package/cli/storybook-dist/assets/{RBPopover.stories-C8iLIZpv.js → RBPopover.stories-C514M09_.js} +1 -1
- package/cli/storybook-dist/assets/{RBPrompt.stories-Th_HrWHI.js → RBPrompt.stories-BSItvfiT.js} +1 -1
- package/cli/storybook-dist/assets/{RBRadioBox.stories-CoHuLaN3.js → RBRadioBox.stories-BBb4YbFU.js} +1 -1
- package/cli/storybook-dist/assets/{RBRadioButton.stories-DULxE_ff.js → RBRadioButton.stories-CXyOGJCv.js} +1 -1
- package/cli/storybook-dist/assets/{RBRangeDateInput.stories-D8A9KBSS.js → RBRangeDateInput.stories-qvhubu0e.js} +1 -1
- package/cli/storybook-dist/assets/{RBResizable.stories-C41QfrQ3.js → RBResizable.stories-CZKeyGjH.js} +14 -14
- package/cli/storybook-dist/assets/{RBSelectBox.stories-C1gNmwzw.js → RBSelectBox.stories-CRKP3ybf.js} +1 -1
- package/cli/storybook-dist/assets/RBSheet.stories-sCM3ZJUa.js +39 -0
- package/cli/storybook-dist/assets/{RBSideNumberInput.stories-9LlgQ8nh.js → RBSideNumberInput.stories-Bb7gw8RF.js} +3 -3
- package/cli/storybook-dist/assets/{RBSlider.stories-oUgo5K9d.js → RBSlider.stories-23OAQU5z.js} +3 -3
- package/cli/storybook-dist/assets/{RBSpinner.stories-DDpohbY2.js → RBSpinner.stories-2xcQdcmt.js} +1 -1
- package/cli/storybook-dist/assets/{RBSwitch.stories-gW-GN7QO.js → RBSwitch.stories-BACUaJm_.js} +7 -7
- package/cli/storybook-dist/assets/{RBTab.stories-CN-PV3HH.js → RBTab.stories-CDHE3sVs.js} +1 -1
- package/cli/storybook-dist/assets/{RBTable.stories-BAZLpxtM.js → RBTable.stories-C0Cfhfl7.js} +29 -29
- package/cli/storybook-dist/assets/{RBTableRow.stories-CwjVrszB.js → RBTableRow.stories-BF8kIkpp.js} +1 -1
- package/cli/storybook-dist/assets/{RBTabs.stories-JuEo2sUL.js → RBTabs.stories-BdJWRq1o.js} +7 -7
- package/cli/storybook-dist/assets/{RBTextArea.stories-D0_Pv4qZ.js → RBTextArea.stories-CGy2xeYH.js} +3 -3
- package/cli/storybook-dist/assets/{RBTextField.stories-CCsOvZqV.js → RBTextField.stories-IfUOzxCM.js} +15 -15
- package/cli/storybook-dist/assets/{RBTextInput.stories-Cccn3VNm.js → RBTextInput.stories-VjXNFo4R.js} +3 -3
- package/cli/storybook-dist/assets/{RBToast.stories-I5617t0K.js → RBToast.stories-BzcobblV.js} +1 -1
- package/cli/storybook-dist/assets/{RBToggle.stories-DsgKjGsJ.js → RBToggle.stories-DuLE5mKv.js} +4 -4
- package/cli/storybook-dist/assets/{RBToggleGroup.stories-BZEzSDuz.js → RBToggleGroup.stories-CuR0N0GJ.js} +5 -5
- package/cli/storybook-dist/assets/{RBTooltip.stories-4oSyAWsA.js → RBTooltip.stories--aAgNC8_.js} +1 -1
- package/cli/storybook-dist/assets/{SideNumberInput-DSKbd0bG.js → SideNumberInput-DyWQxYUj.js} +743 -743
- package/cli/storybook-dist/assets/{entry-preview-B35XREGs.js → entry-preview-D7IHsza_.js} +1 -1
- package/cli/storybook-dist/assets/{iframe-BB797lmL.js → iframe-CbaIp5I-.js} +2 -2
- package/cli/storybook-dist/assets/{index-BU2567EP.js → index-C6CBgMuG.js} +3 -3
- package/cli/storybook-dist/assets/{preview-C7DaSWyc.js → preview-B-iYLDuW.js} +2 -2
- package/cli/storybook-dist/assets/{preview-CbuRHit4.js → preview-CRWqc9DH.js} +1 -1
- package/cli/storybook-dist/assets/{react-resizable-panels.browser-ChIvlwo7.js → react-resizable-panels.browser-8hC8dr-6.js} +8 -8
- package/cli/storybook-dist/iframe.html +2 -2
- package/cli/storybook-dist/index.html +1 -1
- package/cli/storybook-dist/project.json +1 -1
- package/cli/templates/common/.mcp.json +8 -8
- package/cli/templates/common/README.md +1231 -1231
- package/cli/templates/common/assets/icon.svg +45 -45
- package/cli/templates/common/manifest.json +26 -26
- package/cli/templates/common/package.json +22 -22
- package/cli/templates/common/py/main.py +125 -125
- package/cli/templates/common/requirements.txt +4 -4
- package/cli/templates/common/tsconfig.json +13 -13
- package/cli/templates/common/ui/content.tsx +216 -216
- package/cli/templates/common/ui/style.css +6 -6
- package/cli/templates/common/vite.config.ts +10 -10
- package/cli/templates/cpp/cpp/main.cpp +73 -73
- package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/__PLUGIN_SLUG__/node.py +25 -25
- package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/package.xml +10 -10
- package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/setup.py +18 -18
- package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/package.xml +11 -11
- package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/src/node.cpp +23 -23
- package/cli/vite.d.mts +25 -25
- package/cli/vite.mjs +292 -292
- package/package.json +3 -3
- package/cli/storybook-dist/assets/RBCommand.stories-BSqXDkKw.js +0 -73
- package/cli/storybook-dist/assets/RBDialog.stories-BAktz-ku.js +0 -38
- package/cli/storybook-dist/assets/RBDropdownMenu.stories-DbW2fWAj.js +0 -86
- package/cli/storybook-dist/assets/RBSheet.stories-_6VH-RUm.js +0 -39
|
@@ -1,216 +1,216 @@
|
|
|
1
|
-
import { useMemo, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
RBCheckBox,
|
|
4
|
-
RBLabelButton,
|
|
5
|
-
RBRadioBox,
|
|
6
|
-
RBSelectBox,
|
|
7
|
-
RBSlider,
|
|
8
|
-
RBSwitch,
|
|
9
|
-
RBTextArea,
|
|
10
|
-
RBTextField,
|
|
11
|
-
RBTextInput,
|
|
12
|
-
Option
|
|
13
|
-
} from "@rainbow-robotics/plugin-ui/react";
|
|
14
|
-
import { useRb } from "@rainbow-robotics/plugin-ui/sdk";
|
|
15
|
-
|
|
16
|
-
type RunMode = "inspect" | "assist" | "auto";
|
|
17
|
-
|
|
18
|
-
const MODE_OPTIONS: Array<{ label: string; value: RunMode }> = [
|
|
19
|
-
{ label: "Inspect", value: "inspect" },
|
|
20
|
-
{ label: "Assist", value: "assist" },
|
|
21
|
-
{ label: "Auto", value: "auto" },
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
const TASK_OPTIONS = [
|
|
25
|
-
{ label: "Publish status", value: "publish" },
|
|
26
|
-
{ label: "Run grip action", value: "grip" },
|
|
27
|
-
{ label: "Save snapshot", value: "snapshot" },
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
// Export your UI as the default. The host mounts it (dev: with HMR).
|
|
31
|
-
export default function App() {
|
|
32
|
-
const rb = useRb();
|
|
33
|
-
const [targetName, setTargetName] = useState("demo_target");
|
|
34
|
-
const [gripType, setGripType] = useState<string>();
|
|
35
|
-
const [gripWidth, setGripWidth] = useState(24);
|
|
36
|
-
const [speed, setSpeed] = useState(45);
|
|
37
|
-
const [mode, setMode] = useState<RunMode>("assist");
|
|
38
|
-
const [enabled, setEnabled] = useState(true);
|
|
39
|
-
const [tasks, setTasks] = useState<Array<string>>(["publish", "grip"]);
|
|
40
|
-
const [memo, setMemo] = useState("Use this area for operator notes.");
|
|
41
|
-
|
|
42
|
-
const payload = useMemo(
|
|
43
|
-
() => ({
|
|
44
|
-
targetName,
|
|
45
|
-
gripWidth,
|
|
46
|
-
speed,
|
|
47
|
-
mode,
|
|
48
|
-
enabled,
|
|
49
|
-
tasks,
|
|
50
|
-
memo,
|
|
51
|
-
}),
|
|
52
|
-
[targetName, gripWidth, speed, mode, enabled, tasks, memo],
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
const showRequestError = (error: unknown) => {
|
|
56
|
-
const message = error instanceof Error ? error.message : "Request failed";
|
|
57
|
-
rb.toast({ type: "danger", message });
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const runAction = async () => {
|
|
61
|
-
try {
|
|
62
|
-
await rb.action("grip", payload);
|
|
63
|
-
rb.toast({ type: "success", message: `Sent ${targetName}` });
|
|
64
|
-
} catch (error) {
|
|
65
|
-
showRequestError(error);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const publishPreview = async () => {
|
|
70
|
-
try {
|
|
71
|
-
const isConfirm = await rb.confirm({
|
|
72
|
-
message: "Are you sure publish?",
|
|
73
|
-
buttonText: { yes: "confirm", no: "cancel" },
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (isConfirm) {
|
|
77
|
-
await rb.pub("event", payload);
|
|
78
|
-
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
showRequestError(error);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<div className="max-h-[70vh] w-[420px] p-4 max-w-full overflow-y-auto bg-bg-elevated text-fg-default">
|
|
86
|
-
<div className="flex flex-col gap-5">
|
|
87
|
-
<header>
|
|
88
|
-
<div className="flex items-center justify-between gap-12">
|
|
89
|
-
<div>
|
|
90
|
-
<h2 className="typo-heading-xs-semibold">Demo Control</h2>
|
|
91
|
-
<p className="typo-body-xs2-normal text-fg-subtle">
|
|
92
|
-
Input patterns for Muscat plugin UIs
|
|
93
|
-
</p>
|
|
94
|
-
</div>
|
|
95
|
-
<RBSwitch
|
|
96
|
-
checked={enabled}
|
|
97
|
-
onCheckedChange={(next: boolean) => {
|
|
98
|
-
setEnabled(next);
|
|
99
|
-
rb.toast({message: next ? "Plugin enabled" : "Plugin paused"});
|
|
100
|
-
}}
|
|
101
|
-
/>
|
|
102
|
-
</div>
|
|
103
|
-
</header>
|
|
104
|
-
|
|
105
|
-
<section className="flex flex-col gap-4">
|
|
106
|
-
<RBTextField
|
|
107
|
-
label="Target name"
|
|
108
|
-
required
|
|
109
|
-
helperText="Used as the backend action target."
|
|
110
|
-
>
|
|
111
|
-
<RBTextInput
|
|
112
|
-
name="targetName"
|
|
113
|
-
value={targetName}
|
|
114
|
-
placeholder="target id"
|
|
115
|
-
handleChange={(value) => setTargetName(String(value))}
|
|
116
|
-
/>
|
|
117
|
-
</RBTextField>
|
|
118
|
-
|
|
119
|
-
<RBTextField label="Select Grip">
|
|
120
|
-
<RBSelectBox className="w-full" value={gripType} handleChange={setGripType}>
|
|
121
|
-
<Option value="A">A Grip</Option>
|
|
122
|
-
<Option value="B">B Grip</Option>
|
|
123
|
-
</RBSelectBox>
|
|
124
|
-
</RBTextField>
|
|
125
|
-
|
|
126
|
-
<div className="flex gap-4">
|
|
127
|
-
<RBTextField className="flex-1" label="Grip width" helperText="0-100 mm">
|
|
128
|
-
<RBTextInput
|
|
129
|
-
className="w-full"
|
|
130
|
-
name="gripWidth"
|
|
131
|
-
type="number"
|
|
132
|
-
value={gripWidth}
|
|
133
|
-
validate={(value: number) =>
|
|
134
|
-
Math.max(0, Math.min(100, Number(value) || 0))
|
|
135
|
-
}
|
|
136
|
-
handleChange={(value) => setGripWidth(Number(value) || 0)}
|
|
137
|
-
/>
|
|
138
|
-
</RBTextField>
|
|
139
|
-
|
|
140
|
-
<RBTextField className="flex-1" label="Speed" helperText={`${speed}%`}>
|
|
141
|
-
<div className="flex items-center px-2">
|
|
142
|
-
<RBSlider
|
|
143
|
-
value={[speed]}
|
|
144
|
-
min={0}
|
|
145
|
-
max={100}
|
|
146
|
-
step={5}
|
|
147
|
-
onValueChange={(values: number[]) =>
|
|
148
|
-
setSpeed(values[0] ?? 0)
|
|
149
|
-
}
|
|
150
|
-
/>
|
|
151
|
-
</div>
|
|
152
|
-
</RBTextField>
|
|
153
|
-
</div>
|
|
154
|
-
</section>
|
|
155
|
-
|
|
156
|
-
<section className="mb-4">
|
|
157
|
-
<RBTextField label="Run mode">
|
|
158
|
-
<div className="flex justify-between border-1 border-border-subtle rounded-sm p-2">
|
|
159
|
-
{MODE_OPTIONS.map((item) => (
|
|
160
|
-
<RBRadioBox
|
|
161
|
-
key={item.value}
|
|
162
|
-
name="mode"
|
|
163
|
-
checkValue={item.value}
|
|
164
|
-
value={mode}
|
|
165
|
-
handleChange={(value) => setMode(value as RunMode)}
|
|
166
|
-
>
|
|
167
|
-
{item.label}
|
|
168
|
-
</RBRadioBox>
|
|
169
|
-
))}
|
|
170
|
-
</div>
|
|
171
|
-
</RBTextField>
|
|
172
|
-
</section>
|
|
173
|
-
|
|
174
|
-
<section className="mb-4">
|
|
175
|
-
<RBTextField label="Tasks">
|
|
176
|
-
<div className="flex justify-between border-1 border-border-subtle rounded-sm p-2">
|
|
177
|
-
{TASK_OPTIONS.map((item) => (
|
|
178
|
-
<RBCheckBox
|
|
179
|
-
key={item.value}
|
|
180
|
-
name="tasks"
|
|
181
|
-
checkValue={item.value}
|
|
182
|
-
value={tasks}
|
|
183
|
-
handleChange={(value) =>
|
|
184
|
-
setTasks(Array.isArray(value) ? value.map(String) : [])
|
|
185
|
-
}
|
|
186
|
-
>
|
|
187
|
-
{item.label}
|
|
188
|
-
</RBCheckBox>
|
|
189
|
-
))}
|
|
190
|
-
</div>
|
|
191
|
-
</RBTextField>
|
|
192
|
-
|
|
193
|
-
</section>
|
|
194
|
-
|
|
195
|
-
<RBTextField label="Memo">
|
|
196
|
-
<RBTextArea
|
|
197
|
-
name="memo"
|
|
198
|
-
value={memo}
|
|
199
|
-
maxLength={120}
|
|
200
|
-
rows={4}
|
|
201
|
-
handleChange={setMemo}
|
|
202
|
-
/>
|
|
203
|
-
</RBTextField>
|
|
204
|
-
|
|
205
|
-
<footer className="grid grid-cols-2 gap-8 pt-4">
|
|
206
|
-
<RBLabelButton variant="outlined" onClick={publishPreview}>
|
|
207
|
-
Publish
|
|
208
|
-
</RBLabelButton>
|
|
209
|
-
<RBLabelButton onClick={runAction} disabled={!enabled}>
|
|
210
|
-
Run Action
|
|
211
|
-
</RBLabelButton>
|
|
212
|
-
</footer>
|
|
213
|
-
</div>
|
|
214
|
-
</div>
|
|
215
|
-
);
|
|
216
|
-
}
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
RBCheckBox,
|
|
4
|
+
RBLabelButton,
|
|
5
|
+
RBRadioBox,
|
|
6
|
+
RBSelectBox,
|
|
7
|
+
RBSlider,
|
|
8
|
+
RBSwitch,
|
|
9
|
+
RBTextArea,
|
|
10
|
+
RBTextField,
|
|
11
|
+
RBTextInput,
|
|
12
|
+
Option
|
|
13
|
+
} from "@rainbow-robotics/plugin-ui/react";
|
|
14
|
+
import { useRb } from "@rainbow-robotics/plugin-ui/sdk";
|
|
15
|
+
|
|
16
|
+
type RunMode = "inspect" | "assist" | "auto";
|
|
17
|
+
|
|
18
|
+
const MODE_OPTIONS: Array<{ label: string; value: RunMode }> = [
|
|
19
|
+
{ label: "Inspect", value: "inspect" },
|
|
20
|
+
{ label: "Assist", value: "assist" },
|
|
21
|
+
{ label: "Auto", value: "auto" },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const TASK_OPTIONS = [
|
|
25
|
+
{ label: "Publish status", value: "publish" },
|
|
26
|
+
{ label: "Run grip action", value: "grip" },
|
|
27
|
+
{ label: "Save snapshot", value: "snapshot" },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// Export your UI as the default. The host mounts it (dev: with HMR).
|
|
31
|
+
export default function App() {
|
|
32
|
+
const rb = useRb();
|
|
33
|
+
const [targetName, setTargetName] = useState("demo_target");
|
|
34
|
+
const [gripType, setGripType] = useState<string>();
|
|
35
|
+
const [gripWidth, setGripWidth] = useState(24);
|
|
36
|
+
const [speed, setSpeed] = useState(45);
|
|
37
|
+
const [mode, setMode] = useState<RunMode>("assist");
|
|
38
|
+
const [enabled, setEnabled] = useState(true);
|
|
39
|
+
const [tasks, setTasks] = useState<Array<string>>(["publish", "grip"]);
|
|
40
|
+
const [memo, setMemo] = useState("Use this area for operator notes.");
|
|
41
|
+
|
|
42
|
+
const payload = useMemo(
|
|
43
|
+
() => ({
|
|
44
|
+
targetName,
|
|
45
|
+
gripWidth,
|
|
46
|
+
speed,
|
|
47
|
+
mode,
|
|
48
|
+
enabled,
|
|
49
|
+
tasks,
|
|
50
|
+
memo,
|
|
51
|
+
}),
|
|
52
|
+
[targetName, gripWidth, speed, mode, enabled, tasks, memo],
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const showRequestError = (error: unknown) => {
|
|
56
|
+
const message = error instanceof Error ? error.message : "Request failed";
|
|
57
|
+
rb.toast({ type: "danger", message });
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const runAction = async () => {
|
|
61
|
+
try {
|
|
62
|
+
await rb.action("grip", payload);
|
|
63
|
+
rb.toast({ type: "success", message: `Sent ${targetName}` });
|
|
64
|
+
} catch (error) {
|
|
65
|
+
showRequestError(error);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const publishPreview = async () => {
|
|
70
|
+
try {
|
|
71
|
+
const isConfirm = await rb.confirm({
|
|
72
|
+
message: "Are you sure publish?",
|
|
73
|
+
buttonText: { yes: "confirm", no: "cancel" },
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (isConfirm) {
|
|
77
|
+
await rb.pub("event", payload);
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
showRequestError(error);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div className="max-h-[70vh] w-[420px] p-4 max-w-full overflow-y-auto bg-bg-elevated text-fg-default">
|
|
86
|
+
<div className="flex flex-col gap-5">
|
|
87
|
+
<header>
|
|
88
|
+
<div className="flex items-center justify-between gap-12">
|
|
89
|
+
<div>
|
|
90
|
+
<h2 className="typo-heading-xs-semibold">Demo Control</h2>
|
|
91
|
+
<p className="typo-body-xs2-normal text-fg-subtle">
|
|
92
|
+
Input patterns for Muscat plugin UIs
|
|
93
|
+
</p>
|
|
94
|
+
</div>
|
|
95
|
+
<RBSwitch
|
|
96
|
+
checked={enabled}
|
|
97
|
+
onCheckedChange={(next: boolean) => {
|
|
98
|
+
setEnabled(next);
|
|
99
|
+
rb.toast({message: next ? "Plugin enabled" : "Plugin paused"});
|
|
100
|
+
}}
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
103
|
+
</header>
|
|
104
|
+
|
|
105
|
+
<section className="flex flex-col gap-4">
|
|
106
|
+
<RBTextField
|
|
107
|
+
label="Target name"
|
|
108
|
+
required
|
|
109
|
+
helperText="Used as the backend action target."
|
|
110
|
+
>
|
|
111
|
+
<RBTextInput
|
|
112
|
+
name="targetName"
|
|
113
|
+
value={targetName}
|
|
114
|
+
placeholder="target id"
|
|
115
|
+
handleChange={(value) => setTargetName(String(value))}
|
|
116
|
+
/>
|
|
117
|
+
</RBTextField>
|
|
118
|
+
|
|
119
|
+
<RBTextField label="Select Grip">
|
|
120
|
+
<RBSelectBox className="w-full" value={gripType} handleChange={setGripType}>
|
|
121
|
+
<Option value="A">A Grip</Option>
|
|
122
|
+
<Option value="B">B Grip</Option>
|
|
123
|
+
</RBSelectBox>
|
|
124
|
+
</RBTextField>
|
|
125
|
+
|
|
126
|
+
<div className="flex gap-4">
|
|
127
|
+
<RBTextField className="flex-1" label="Grip width" helperText="0-100 mm">
|
|
128
|
+
<RBTextInput
|
|
129
|
+
className="w-full"
|
|
130
|
+
name="gripWidth"
|
|
131
|
+
type="number"
|
|
132
|
+
value={gripWidth}
|
|
133
|
+
validate={(value: number) =>
|
|
134
|
+
Math.max(0, Math.min(100, Number(value) || 0))
|
|
135
|
+
}
|
|
136
|
+
handleChange={(value) => setGripWidth(Number(value) || 0)}
|
|
137
|
+
/>
|
|
138
|
+
</RBTextField>
|
|
139
|
+
|
|
140
|
+
<RBTextField className="flex-1" label="Speed" helperText={`${speed}%`}>
|
|
141
|
+
<div className="flex items-center px-2">
|
|
142
|
+
<RBSlider
|
|
143
|
+
value={[speed]}
|
|
144
|
+
min={0}
|
|
145
|
+
max={100}
|
|
146
|
+
step={5}
|
|
147
|
+
onValueChange={(values: number[]) =>
|
|
148
|
+
setSpeed(values[0] ?? 0)
|
|
149
|
+
}
|
|
150
|
+
/>
|
|
151
|
+
</div>
|
|
152
|
+
</RBTextField>
|
|
153
|
+
</div>
|
|
154
|
+
</section>
|
|
155
|
+
|
|
156
|
+
<section className="mb-4">
|
|
157
|
+
<RBTextField label="Run mode">
|
|
158
|
+
<div className="flex justify-between border-1 border-border-subtle rounded-sm p-2">
|
|
159
|
+
{MODE_OPTIONS.map((item) => (
|
|
160
|
+
<RBRadioBox
|
|
161
|
+
key={item.value}
|
|
162
|
+
name="mode"
|
|
163
|
+
checkValue={item.value}
|
|
164
|
+
value={mode}
|
|
165
|
+
handleChange={(value) => setMode(value as RunMode)}
|
|
166
|
+
>
|
|
167
|
+
{item.label}
|
|
168
|
+
</RBRadioBox>
|
|
169
|
+
))}
|
|
170
|
+
</div>
|
|
171
|
+
</RBTextField>
|
|
172
|
+
</section>
|
|
173
|
+
|
|
174
|
+
<section className="mb-4">
|
|
175
|
+
<RBTextField label="Tasks">
|
|
176
|
+
<div className="flex justify-between border-1 border-border-subtle rounded-sm p-2">
|
|
177
|
+
{TASK_OPTIONS.map((item) => (
|
|
178
|
+
<RBCheckBox
|
|
179
|
+
key={item.value}
|
|
180
|
+
name="tasks"
|
|
181
|
+
checkValue={item.value}
|
|
182
|
+
value={tasks}
|
|
183
|
+
handleChange={(value) =>
|
|
184
|
+
setTasks(Array.isArray(value) ? value.map(String) : [])
|
|
185
|
+
}
|
|
186
|
+
>
|
|
187
|
+
{item.label}
|
|
188
|
+
</RBCheckBox>
|
|
189
|
+
))}
|
|
190
|
+
</div>
|
|
191
|
+
</RBTextField>
|
|
192
|
+
|
|
193
|
+
</section>
|
|
194
|
+
|
|
195
|
+
<RBTextField label="Memo">
|
|
196
|
+
<RBTextArea
|
|
197
|
+
name="memo"
|
|
198
|
+
value={memo}
|
|
199
|
+
maxLength={120}
|
|
200
|
+
rows={4}
|
|
201
|
+
handleChange={setMemo}
|
|
202
|
+
/>
|
|
203
|
+
</RBTextField>
|
|
204
|
+
|
|
205
|
+
<footer className="grid grid-cols-2 gap-8 pt-4">
|
|
206
|
+
<RBLabelButton variant="outlined" onClick={publishPreview}>
|
|
207
|
+
Publish
|
|
208
|
+
</RBLabelButton>
|
|
209
|
+
<RBLabelButton onClick={runAction} disabled={!enabled}>
|
|
210
|
+
Run Action
|
|
211
|
+
</RBLabelButton>
|
|
212
|
+
</footer>
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
@layer theme, utilities;
|
|
2
|
-
|
|
3
|
-
@import "tailwindcss/theme.css" layer(theme);
|
|
4
|
-
@import "tailwindcss/utilities.css" layer(utilities);
|
|
5
|
-
|
|
6
|
-
@source "./**/*.{ts,tsx}";
|
|
1
|
+
@layer theme, utilities;
|
|
2
|
+
|
|
3
|
+
@import "tailwindcss/theme.css" layer(theme);
|
|
4
|
+
@import "tailwindcss/utilities.css" layer(utilities);
|
|
5
|
+
|
|
6
|
+
@source "./**/*.{ts,tsx}";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defineConfig } from "vite";
|
|
2
|
-
import tailwindcss from "@tailwindcss/vite";
|
|
3
|
-
import { muscat } from "@rainbow-robotics/muscat-plugin-kit/vite";
|
|
4
|
-
|
|
5
|
-
// The muscat() preset wires react-refresh, ui/ entry discovery, and marks the
|
|
6
|
-
// host-provided runtime (plugin-ui, react) as external. Add your own plugins or
|
|
7
|
-
// overrides here as needed.
|
|
8
|
-
export default defineConfig({
|
|
9
|
-
plugins: [tailwindcss(), muscat()],
|
|
10
|
-
});
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
3
|
+
import { muscat } from "@rainbow-robotics/muscat-plugin-kit/vite";
|
|
4
|
+
|
|
5
|
+
// The muscat() preset wires react-refresh, ui/ entry discovery, and marks the
|
|
6
|
+
// host-provided runtime (plugin-ui, react) as external. Add your own plugins or
|
|
7
|
+
// overrides here as needed.
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
plugins: [tailwindcss(), muscat()],
|
|
10
|
+
});
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
// __PLUGIN_NAME__ — C++ plugin back end.
|
|
2
|
-
//
|
|
3
|
-
// The Rainbow Robotics C++ SDK (apt: rainbow-rb-sdk-dev) is installed in the
|
|
4
|
-
// dev container and linked via CMake (rb_sdk::rb_sdk). Headers live under
|
|
5
|
-
// <rainbow/rb_sdk/...>:
|
|
6
|
-
// - plugin/rb_plugin.hpp rb_plugin::RBPluginCall — plugin UI <-> backend
|
|
7
|
-
// (serve/subscribe/publish) and external endpoints (router)
|
|
8
|
-
// - manipulate/rb_manipulate_sdk.hpp RBManipulateSDK — control the robot
|
|
9
|
-
// - program/plugin_program_context.hpp rb_plugin::PluginProgramContext —
|
|
10
|
-
// program.panel commands (done/pause/stop,
|
|
11
|
-
// program variables)
|
|
12
|
-
|
|
13
|
-
#include <rainbow/rb_sdk/manipulate/rb_manipulate_sdk.hpp>
|
|
14
|
-
#include <rainbow/rb_sdk/plugin/rb_plugin.hpp>
|
|
15
|
-
|
|
16
|
-
#include <nlohmann/json.hpp>
|
|
17
|
-
|
|
18
|
-
#include <chrono>
|
|
19
|
-
#include <cstdlib>
|
|
20
|
-
#include <iostream>
|
|
21
|
-
#include <string>
|
|
22
|
-
#include <thread>
|
|
23
|
-
|
|
24
|
-
using nlohmann::json;
|
|
25
|
-
using rb_plugin::RBPluginCall;
|
|
26
|
-
|
|
27
|
-
int main() {
|
|
28
|
-
const std::string name = "__PLUGIN_NAME__";
|
|
29
|
-
|
|
30
|
-
// Remote dev: connect before registering handlers (connect() reopens the session).
|
|
31
|
-
RBManipulateSDK manipulate;
|
|
32
|
-
const char* host = std::getenv("MUSCAT_ROBOT_HOST");
|
|
33
|
-
const char* token = std::getenv("MUSCAT_ROBOT_TOKEN");
|
|
34
|
-
if (host && token) manipulate.connect({.token = token, .host = host});
|
|
35
|
-
|
|
36
|
-
// plugin id comes from RB_PLUGIN_ID.
|
|
37
|
-
auto plugin = RBPluginCall::get_instance(RBPluginCall::resolve_plugin_id(std::nullopt));
|
|
38
|
-
|
|
39
|
-
// --- Plugin UI <-> backend (not reachable from outside Muscat) ---
|
|
40
|
-
|
|
41
|
-
// UI: await rb.action("grip", { width })
|
|
42
|
-
plugin->serve("grip", [&](const json& payload) {
|
|
43
|
-
const int width = payload.is_object() ? payload.value("width", 20) : 20;
|
|
44
|
-
std::cout << "[" << name << "] grip requested: width=" << width << std::endl;
|
|
45
|
-
plugin->publish("state", {{"ready", true}, {"last_grip_width", width}}); // -> rb.sub("state")
|
|
46
|
-
return json{{"ok", true}, {"width", width}};
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// UI: rb.pub("event", ...)
|
|
50
|
-
auto event_sub = plugin->subscribe("event", [&](const std::string&, const json& payload) {
|
|
51
|
-
std::cout << "[" << name << "] event: " << payload.dump() << std::endl;
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// --- External endpoints (REST / Socket.IO / TCP / MQTT / WebRTC) ---
|
|
55
|
-
// curl -X POST http://<robot>/common/plugin/<plugin_id>/hello -d '{"name":"kim"}'
|
|
56
|
-
plugin->router().on("/hello", [](const json& payload, const json& meta) {
|
|
57
|
-
const std::string who = payload.is_object() ? payload.value("name", std::string("there")) : "there";
|
|
58
|
-
return json{{"msg", "hi " + who}, {"via", meta.value("transport", std::string())}};
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Example: robot control (not called automatically — add safety checks first).
|
|
62
|
-
// IPC::MoveInput_TargetT t; t.tar_values = {0, 0, 0, 0, 0, 0};
|
|
63
|
-
// manipulate.move.call_move_j("C500920", t);
|
|
64
|
-
|
|
65
|
-
plugin->publish("state", {{"ready", true}, {"plugin", name}});
|
|
66
|
-
std::cout << "[" << name << "] backend ready" << std::endl;
|
|
67
|
-
|
|
68
|
-
// Keep the process alive.
|
|
69
|
-
while (true) {
|
|
70
|
-
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
71
|
-
}
|
|
72
|
-
return 0;
|
|
73
|
-
}
|
|
1
|
+
// __PLUGIN_NAME__ — C++ plugin back end.
|
|
2
|
+
//
|
|
3
|
+
// The Rainbow Robotics C++ SDK (apt: rainbow-rb-sdk-dev) is installed in the
|
|
4
|
+
// dev container and linked via CMake (rb_sdk::rb_sdk). Headers live under
|
|
5
|
+
// <rainbow/rb_sdk/...>:
|
|
6
|
+
// - plugin/rb_plugin.hpp rb_plugin::RBPluginCall — plugin UI <-> backend
|
|
7
|
+
// (serve/subscribe/publish) and external endpoints (router)
|
|
8
|
+
// - manipulate/rb_manipulate_sdk.hpp RBManipulateSDK — control the robot
|
|
9
|
+
// - program/plugin_program_context.hpp rb_plugin::PluginProgramContext —
|
|
10
|
+
// program.panel commands (done/pause/stop,
|
|
11
|
+
// program variables)
|
|
12
|
+
|
|
13
|
+
#include <rainbow/rb_sdk/manipulate/rb_manipulate_sdk.hpp>
|
|
14
|
+
#include <rainbow/rb_sdk/plugin/rb_plugin.hpp>
|
|
15
|
+
|
|
16
|
+
#include <nlohmann/json.hpp>
|
|
17
|
+
|
|
18
|
+
#include <chrono>
|
|
19
|
+
#include <cstdlib>
|
|
20
|
+
#include <iostream>
|
|
21
|
+
#include <string>
|
|
22
|
+
#include <thread>
|
|
23
|
+
|
|
24
|
+
using nlohmann::json;
|
|
25
|
+
using rb_plugin::RBPluginCall;
|
|
26
|
+
|
|
27
|
+
int main() {
|
|
28
|
+
const std::string name = "__PLUGIN_NAME__";
|
|
29
|
+
|
|
30
|
+
// Remote dev: connect before registering handlers (connect() reopens the session).
|
|
31
|
+
RBManipulateSDK manipulate;
|
|
32
|
+
const char* host = std::getenv("MUSCAT_ROBOT_HOST");
|
|
33
|
+
const char* token = std::getenv("MUSCAT_ROBOT_TOKEN");
|
|
34
|
+
if (host && token) manipulate.connect({.token = token, .host = host});
|
|
35
|
+
|
|
36
|
+
// plugin id comes from RB_PLUGIN_ID.
|
|
37
|
+
auto plugin = RBPluginCall::get_instance(RBPluginCall::resolve_plugin_id(std::nullopt));
|
|
38
|
+
|
|
39
|
+
// --- Plugin UI <-> backend (not reachable from outside Muscat) ---
|
|
40
|
+
|
|
41
|
+
// UI: await rb.action("grip", { width })
|
|
42
|
+
plugin->serve("grip", [&](const json& payload) {
|
|
43
|
+
const int width = payload.is_object() ? payload.value("width", 20) : 20;
|
|
44
|
+
std::cout << "[" << name << "] grip requested: width=" << width << std::endl;
|
|
45
|
+
plugin->publish("state", {{"ready", true}, {"last_grip_width", width}}); // -> rb.sub("state")
|
|
46
|
+
return json{{"ok", true}, {"width", width}};
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// UI: rb.pub("event", ...)
|
|
50
|
+
auto event_sub = plugin->subscribe("event", [&](const std::string&, const json& payload) {
|
|
51
|
+
std::cout << "[" << name << "] event: " << payload.dump() << std::endl;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// --- External endpoints (REST / Socket.IO / TCP / MQTT / WebRTC) ---
|
|
55
|
+
// curl -X POST http://<robot>/common/plugin/<plugin_id>/hello -d '{"name":"kim"}'
|
|
56
|
+
plugin->router().on("/hello", [](const json& payload, const json& meta) {
|
|
57
|
+
const std::string who = payload.is_object() ? payload.value("name", std::string("there")) : "there";
|
|
58
|
+
return json{{"msg", "hi " + who}, {"via", meta.value("transport", std::string())}};
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Example: robot control (not called automatically — add safety checks first).
|
|
62
|
+
// IPC::MoveInput_TargetT t; t.tar_values = {0, 0, 0, 0, 0, 0};
|
|
63
|
+
// manipulate.move.call_move_j("C500920", t);
|
|
64
|
+
|
|
65
|
+
plugin->publish("state", {{"ready", true}, {"plugin", name}});
|
|
66
|
+
std::cout << "[" << name << "] backend ready" << std::endl;
|
|
67
|
+
|
|
68
|
+
// Keep the process alive.
|
|
69
|
+
while (true) {
|
|
70
|
+
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
71
|
+
}
|
|
72
|
+
return 0;
|
|
73
|
+
}
|