@dxos/plugin-script 0.7.4 → 0.7.5-labs.a279d8c

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.
Files changed (255) hide show
  1. package/dist/lib/browser/{AutomationPanel-PMTZROAZ.mjs → AutomationPanel-OOIRJFPJ.mjs} +4 -11
  2. package/dist/lib/browser/AutomationPanel-OOIRJFPJ.mjs.map +7 -0
  3. package/dist/lib/browser/ScriptContainer-T2AOMDT3.mjs +685 -0
  4. package/dist/lib/browser/ScriptContainer-T2AOMDT3.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-C7VBULMK.mjs → chunk-5BU5ERNU.mjs} +3 -3
  6. package/dist/lib/browser/chunk-5BU5ERNU.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-REL2R7SB.mjs +52 -0
  8. package/dist/lib/browser/chunk-REL2R7SB.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-4UTRJLQ3.mjs → chunk-SDHKTS6H.mjs} +2 -51
  10. package/dist/lib/browser/{chunk-4UTRJLQ3.mjs.map → chunk-SDHKTS6H.mjs.map} +4 -4
  11. package/dist/lib/browser/chunk-SIOGRRPF.mjs +224 -0
  12. package/dist/lib/browser/chunk-SIOGRRPF.mjs.map +7 -0
  13. package/dist/lib/browser/{chunk-K7KY6YMG.mjs → chunk-SJ4J527G.mjs} +2 -2
  14. package/dist/lib/browser/chunk-XPGBHZ3L.mjs +40 -0
  15. package/dist/lib/browser/chunk-XPGBHZ3L.mjs.map +7 -0
  16. package/dist/lib/browser/chunk-ZM6T4HPR.mjs +15 -0
  17. package/dist/lib/browser/chunk-ZM6T4HPR.mjs.map +7 -0
  18. package/dist/lib/browser/compiler-HT53ILG7.mjs +84 -0
  19. package/dist/lib/browser/compiler-HT53ILG7.mjs.map +7 -0
  20. package/dist/lib/browser/index.mjs +107 -357
  21. package/dist/lib/browser/index.mjs.map +4 -4
  22. package/dist/lib/browser/intent-resolver-YPHT6HDZ.mjs +42 -0
  23. package/dist/lib/browser/intent-resolver-YPHT6HDZ.mjs.map +7 -0
  24. package/dist/lib/browser/meta.json +1 -1
  25. package/dist/lib/browser/react-surface-GAWVYTJ5.mjs +67 -0
  26. package/dist/lib/browser/react-surface-GAWVYTJ5.mjs.map +7 -0
  27. package/dist/lib/browser/settings-YQQEU3DF.mjs +24 -0
  28. package/dist/lib/browser/settings-YQQEU3DF.mjs.map +7 -0
  29. package/dist/lib/browser/types.mjs +10 -0
  30. package/dist/lib/node/{AutomationPanel-AAGQREH7.cjs → AutomationPanel-EPRDDR3A.cjs} +16 -17
  31. package/dist/lib/node/AutomationPanel-EPRDDR3A.cjs.map +7 -0
  32. package/dist/lib/node/ScriptContainer-BV56I4OL.cjs +689 -0
  33. package/dist/lib/node/ScriptContainer-BV56I4OL.cjs.map +7 -0
  34. package/dist/lib/node/chunk-5V3XGLTR.cjs +252 -0
  35. package/dist/lib/node/chunk-5V3XGLTR.cjs.map +7 -0
  36. package/dist/lib/node/chunk-6VKZJ4MH.cjs +60 -0
  37. package/dist/lib/node/chunk-6VKZJ4MH.cjs.map +7 -0
  38. package/dist/lib/node/{meta.cjs → chunk-A2DI2G4D.cjs} +12 -8
  39. package/dist/lib/node/chunk-A2DI2G4D.cjs.map +7 -0
  40. package/dist/lib/node/{chunk-4INUJLXL.cjs → chunk-DQRAVZM7.cjs} +6 -6
  41. package/dist/lib/node/{chunk-6LYX73ZT.cjs → chunk-EFTZN5X7.cjs} +7 -7
  42. package/dist/lib/node/chunk-EFTZN5X7.cjs.map +7 -0
  43. package/dist/lib/node/{chunk-WPP65EYS.cjs → chunk-T4TXCRN5.cjs} +6 -44
  44. package/dist/lib/node/chunk-T4TXCRN5.cjs.map +7 -0
  45. package/dist/lib/node/chunk-TJ4BTPOS.cjs +64 -0
  46. package/dist/lib/node/chunk-TJ4BTPOS.cjs.map +7 -0
  47. package/dist/lib/node/compiler-457ZR24G.cjs +104 -0
  48. package/dist/lib/node/compiler-457ZR24G.cjs.map +7 -0
  49. package/dist/lib/node/index.cjs +104 -346
  50. package/dist/lib/node/index.cjs.map +4 -4
  51. package/dist/lib/node/intent-resolver-SUAPE7H3.cjs +56 -0
  52. package/dist/lib/node/intent-resolver-SUAPE7H3.cjs.map +7 -0
  53. package/dist/lib/node/meta.json +1 -1
  54. package/dist/lib/node/react-surface-OMBMSFZT.cjs +86 -0
  55. package/dist/lib/node/react-surface-OMBMSFZT.cjs.map +7 -0
  56. package/dist/lib/node/settings-NGHDYAVK.cjs +38 -0
  57. package/dist/lib/node/settings-NGHDYAVK.cjs.map +7 -0
  58. package/dist/lib/node/{types/index.cjs → types.cjs} +6 -8
  59. package/dist/lib/node/types.cjs.map +7 -0
  60. package/dist/lib/node-esm/{AutomationPanel-ETQEDY5I.mjs → AutomationPanel-DMLAGQS5.mjs} +4 -11
  61. package/dist/lib/node-esm/AutomationPanel-DMLAGQS5.mjs.map +7 -0
  62. package/dist/lib/node-esm/ScriptContainer-3S5VHJVR.mjs +686 -0
  63. package/dist/lib/node-esm/ScriptContainer-3S5VHJVR.mjs.map +7 -0
  64. package/dist/lib/node-esm/chunk-675XSDRN.mjs +16 -0
  65. package/dist/lib/node-esm/chunk-675XSDRN.mjs.map +7 -0
  66. package/dist/lib/node-esm/{chunk-SLTZMY34.mjs → chunk-BHP545D7.mjs} +3 -3
  67. package/dist/lib/node-esm/chunk-BHP545D7.mjs.map +7 -0
  68. package/dist/lib/node-esm/{chunk-4SRPREUK.mjs → chunk-G76M6O46.mjs} +2 -51
  69. package/dist/lib/node-esm/{chunk-4SRPREUK.mjs.map → chunk-G76M6O46.mjs.map} +4 -4
  70. package/dist/lib/node-esm/chunk-JHGOPQVO.mjs +41 -0
  71. package/dist/lib/node-esm/chunk-JHGOPQVO.mjs.map +7 -0
  72. package/dist/lib/node-esm/chunk-JJZYWSD7.mjs +54 -0
  73. package/dist/lib/node-esm/chunk-JJZYWSD7.mjs.map +7 -0
  74. package/dist/lib/node-esm/chunk-XPIKUBGS.mjs +225 -0
  75. package/dist/lib/node-esm/chunk-XPIKUBGS.mjs.map +7 -0
  76. package/dist/lib/node-esm/{chunk-OFYGBUNI.mjs → chunk-XUWS7OTK.mjs} +2 -2
  77. package/dist/lib/node-esm/compiler-PEARFTFR.mjs +85 -0
  78. package/dist/lib/node-esm/compiler-PEARFTFR.mjs.map +7 -0
  79. package/dist/lib/node-esm/index.mjs +107 -357
  80. package/dist/lib/node-esm/index.mjs.map +4 -4
  81. package/dist/lib/node-esm/intent-resolver-SZJXQ3CW.mjs +43 -0
  82. package/dist/lib/node-esm/intent-resolver-SZJXQ3CW.mjs.map +7 -0
  83. package/dist/lib/node-esm/meta.json +1 -1
  84. package/dist/lib/node-esm/react-surface-J7NLV2V4.mjs +68 -0
  85. package/dist/lib/node-esm/react-surface-J7NLV2V4.mjs.map +7 -0
  86. package/dist/lib/node-esm/settings-XGXDY4NI.mjs +25 -0
  87. package/dist/lib/node-esm/settings-XGXDY4NI.mjs.map +7 -0
  88. package/dist/lib/node-esm/types.mjs +11 -0
  89. package/dist/types/src/ScriptPlugin.d.ts +1 -3
  90. package/dist/types/src/ScriptPlugin.d.ts.map +1 -1
  91. package/dist/types/src/capabilities/capabilities.d.ts +5 -0
  92. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
  93. package/dist/types/src/capabilities/compiler.d.ts +4 -0
  94. package/dist/types/src/capabilities/compiler.d.ts.map +1 -0
  95. package/dist/types/src/capabilities/index.d.ts +6 -0
  96. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  97. package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
  98. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
  99. package/dist/types/src/capabilities/react-surface.d.ts +4 -0
  100. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  101. package/dist/types/src/capabilities/settings.d.ts +4 -0
  102. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  103. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +2 -2
  104. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +1 -1
  105. package/dist/types/src/components/ScriptContainer.d.ts +10 -2
  106. package/dist/types/src/components/ScriptContainer.d.ts.map +1 -1
  107. package/dist/types/src/components/ScriptSettings/ScriptSettings.d.ts.map +1 -1
  108. package/dist/types/src/components/ScriptSettingsPanel.d.ts +1 -1
  109. package/dist/types/src/components/ScriptSettingsPanel.d.ts.map +1 -1
  110. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.d.ts +11 -0
  111. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.d.ts.map +1 -0
  112. package/dist/types/src/components/{Toolbar/Toolbar.stories.d.ts → ScriptToolbar/ScriptToolbar.stories.d.ts} +1 -1
  113. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.stories.d.ts.map +1 -0
  114. package/dist/types/src/components/ScriptToolbar/deploy.d.ts +48 -0
  115. package/dist/types/src/components/ScriptToolbar/deploy.d.ts.map +1 -0
  116. package/dist/types/src/components/ScriptToolbar/format.d.ts +25 -0
  117. package/dist/types/src/components/ScriptToolbar/format.d.ts.map +1 -0
  118. package/dist/types/src/components/ScriptToolbar/index.d.ts +2 -0
  119. package/dist/types/src/components/ScriptToolbar/index.d.ts.map +1 -0
  120. package/dist/types/src/components/ScriptToolbar/templateSelect.d.ts +31 -0
  121. package/dist/types/src/components/ScriptToolbar/templateSelect.d.ts.map +1 -0
  122. package/dist/types/src/components/ScriptToolbar/useToolbarAction.d.ts +14 -0
  123. package/dist/types/src/components/ScriptToolbar/useToolbarAction.d.ts.map +1 -0
  124. package/dist/types/src/components/ScriptToolbar/useToolbarState.d.ts +10 -0
  125. package/dist/types/src/components/ScriptToolbar/useToolbarState.d.ts.map +1 -0
  126. package/dist/types/src/components/ScriptToolbar/view.d.ts +33 -0
  127. package/dist/types/src/components/ScriptToolbar/view.d.ts.map +1 -0
  128. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.d.ts +4 -2
  129. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.d.ts.map +1 -1
  130. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.stories.d.ts.map +1 -1
  131. package/dist/types/src/components/index.d.ts +1 -1
  132. package/dist/types/src/components/index.d.ts.map +1 -1
  133. package/dist/types/src/index.d.ts +2 -4
  134. package/dist/types/src/index.d.ts.map +1 -1
  135. package/dist/types/src/meta.d.ts +1 -2
  136. package/dist/types/src/meta.d.ts.map +1 -1
  137. package/dist/types/src/templates/email.d.ts +2 -1
  138. package/dist/types/src/templates/email.d.ts.map +1 -1
  139. package/dist/types/src/{templates.d.ts → templates/index.d.ts} +1 -1
  140. package/dist/types/src/templates/index.d.ts.map +1 -0
  141. package/dist/types/src/translations.d.ts +48 -0
  142. package/dist/types/src/translations.d.ts.map +1 -1
  143. package/dist/types/src/types.d.ts +30 -0
  144. package/dist/types/src/types.d.ts.map +1 -0
  145. package/dist/types/tsconfig.tsbuildinfo +1 -0
  146. package/package.json +45 -55
  147. package/src/ScriptPlugin.tsx +65 -145
  148. package/src/bundler/bundler.test.ts +4 -3
  149. package/src/capabilities/capabilities.ts +12 -0
  150. package/src/capabilities/compiler.ts +33 -0
  151. package/src/capabilities/index.ts +12 -0
  152. package/src/capabilities/intent-resolver.ts +43 -0
  153. package/src/capabilities/react-surface.tsx +54 -0
  154. package/src/capabilities/settings.ts +14 -0
  155. package/src/compiler/compiler.browser.test.ts +1 -1
  156. package/src/components/AutomationPanel/AutomationPanel.tsx +2 -4
  157. package/src/components/FrameContainer/FrameContainer.tsx +1 -1
  158. package/src/components/ScriptContainer.tsx +64 -9
  159. package/src/components/ScriptSettings/ScriptSettings.tsx +25 -1
  160. package/src/components/ScriptSettingsPanel.tsx +125 -52
  161. package/src/components/{Toolbar/Toolbar.stories.tsx → ScriptToolbar/ScriptToolbar.stories.tsx} +2 -2
  162. package/src/components/ScriptToolbar/ScriptToolbar.tsx +51 -0
  163. package/src/components/ScriptToolbar/deploy.ts +157 -0
  164. package/src/components/ScriptToolbar/format.ts +47 -0
  165. package/src/components/{Toolbar → ScriptToolbar}/index.ts +1 -1
  166. package/src/components/ScriptToolbar/templateSelect.ts +64 -0
  167. package/src/components/ScriptToolbar/useToolbarAction.ts +54 -0
  168. package/src/components/ScriptToolbar/useToolbarState.ts +16 -0
  169. package/src/components/ScriptToolbar/view.ts +52 -0
  170. package/src/components/TypescriptEditor/TypescriptEditor.stories.tsx +2 -0
  171. package/src/components/TypescriptEditor/TypescriptEditor.tsx +73 -8
  172. package/src/index.ts +2 -6
  173. package/src/meta.ts +1 -1
  174. package/src/templates/email.ts +26 -23
  175. package/src/{templates.ts → templates/index.ts} +5 -5
  176. package/src/translations.ts +18 -1
  177. package/src/types.ts +39 -0
  178. package/dist/lib/browser/AutomationPanel-PMTZROAZ.mjs.map +0 -7
  179. package/dist/lib/browser/ScriptContainer-RYZFYCNK.mjs +0 -425
  180. package/dist/lib/browser/ScriptContainer-RYZFYCNK.mjs.map +0 -7
  181. package/dist/lib/browser/chunk-C7VBULMK.mjs.map +0 -7
  182. package/dist/lib/browser/chunk-QFZUFT5G.mjs +0 -48
  183. package/dist/lib/browser/chunk-QFZUFT5G.mjs.map +0 -7
  184. package/dist/lib/browser/chunk-U3OP64V4.mjs +0 -123
  185. package/dist/lib/browser/chunk-U3OP64V4.mjs.map +0 -7
  186. package/dist/lib/browser/edge/index.mjs +0 -19
  187. package/dist/lib/browser/meta.mjs +0 -9
  188. package/dist/lib/browser/types/index.mjs +0 -12
  189. package/dist/lib/browser/types/index.mjs.map +0 -7
  190. package/dist/lib/node/AutomationPanel-AAGQREH7.cjs.map +0 -7
  191. package/dist/lib/node/ScriptContainer-FZ44UIRC.cjs +0 -427
  192. package/dist/lib/node/ScriptContainer-FZ44UIRC.cjs.map +0 -7
  193. package/dist/lib/node/chunk-6LYX73ZT.cjs.map +0 -7
  194. package/dist/lib/node/chunk-CS25QNKZ.cjs +0 -151
  195. package/dist/lib/node/chunk-CS25QNKZ.cjs.map +0 -7
  196. package/dist/lib/node/chunk-DQYAU2CJ.cjs +0 -67
  197. package/dist/lib/node/chunk-DQYAU2CJ.cjs.map +0 -7
  198. package/dist/lib/node/chunk-WPP65EYS.cjs.map +0 -7
  199. package/dist/lib/node/edge/index.cjs +0 -41
  200. package/dist/lib/node/edge/index.cjs.map +0 -7
  201. package/dist/lib/node/meta.cjs.map +0 -7
  202. package/dist/lib/node/types/index.cjs.map +0 -7
  203. package/dist/lib/node-esm/AutomationPanel-ETQEDY5I.mjs.map +0 -7
  204. package/dist/lib/node-esm/ScriptContainer-3PKDW34A.mjs +0 -426
  205. package/dist/lib/node-esm/ScriptContainer-3PKDW34A.mjs.map +0 -7
  206. package/dist/lib/node-esm/chunk-36DLLQ6E.mjs +0 -125
  207. package/dist/lib/node-esm/chunk-36DLLQ6E.mjs.map +0 -7
  208. package/dist/lib/node-esm/chunk-GMVPKT6A.mjs +0 -49
  209. package/dist/lib/node-esm/chunk-GMVPKT6A.mjs.map +0 -7
  210. package/dist/lib/node-esm/chunk-SLTZMY34.mjs.map +0 -7
  211. package/dist/lib/node-esm/edge/index.mjs +0 -20
  212. package/dist/lib/node-esm/edge/index.mjs.map +0 -7
  213. package/dist/lib/node-esm/meta.mjs +0 -10
  214. package/dist/lib/node-esm/meta.mjs.map +0 -7
  215. package/dist/lib/node-esm/types/index.mjs +0 -13
  216. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  217. package/dist/types/src/components/ScriptBlock/ScriptBlock.d.ts +0 -12
  218. package/dist/types/src/components/ScriptBlock/ScriptBlock.d.ts.map +0 -1
  219. package/dist/types/src/components/ScriptBlock/ScriptBlock.stories.d.ts +0 -6
  220. package/dist/types/src/components/ScriptBlock/ScriptBlock.stories.d.ts.map +0 -1
  221. package/dist/types/src/components/ScriptBlock/index.d.ts +0 -2
  222. package/dist/types/src/components/ScriptBlock/index.d.ts.map +0 -1
  223. package/dist/types/src/components/ScriptEditor.d.ts +0 -9
  224. package/dist/types/src/components/ScriptEditor.d.ts.map +0 -1
  225. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -23
  226. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  227. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +0 -1
  228. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  229. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  230. package/dist/types/src/edge/functions.d.ts +0 -25
  231. package/dist/types/src/edge/functions.d.ts.map +0 -1
  232. package/dist/types/src/edge/index.d.ts +0 -2
  233. package/dist/types/src/edge/index.d.ts.map +0 -1
  234. package/dist/types/src/templates.d.ts.map +0 -1
  235. package/dist/types/src/types/index.d.ts +0 -3
  236. package/dist/types/src/types/index.d.ts.map +0 -1
  237. package/dist/types/src/types/schema.d.ts +0 -71
  238. package/dist/types/src/types/schema.d.ts.map +0 -1
  239. package/dist/types/src/types/types.d.ts +0 -8
  240. package/dist/types/src/types/types.d.ts.map +0 -1
  241. package/src/components/ScriptBlock/ScriptBlock.stories.tsx +0 -52
  242. package/src/components/ScriptBlock/ScriptBlock.tsx +0 -102
  243. package/src/components/ScriptBlock/index.ts +0 -5
  244. package/src/components/ScriptEditor.tsx +0 -191
  245. package/src/components/Toolbar/Toolbar.tsx +0 -177
  246. package/src/edge/functions.ts +0 -116
  247. package/src/edge/index.ts +0 -7
  248. package/src/types/index.ts +0 -6
  249. package/src/types/schema.ts +0 -44
  250. package/src/types/types.ts +0 -29
  251. /package/dist/lib/browser/{chunk-K7KY6YMG.mjs.map → chunk-SJ4J527G.mjs.map} +0 -0
  252. /package/dist/lib/browser/{edge/index.mjs.map → types.mjs.map} +0 -0
  253. /package/dist/lib/node/{chunk-4INUJLXL.cjs.map → chunk-DQRAVZM7.cjs.map} +0 -0
  254. /package/dist/lib/node-esm/{chunk-OFYGBUNI.mjs.map → chunk-XUWS7OTK.mjs.map} +0 -0
  255. /package/dist/lib/{browser/meta.mjs.map → node-esm/types.mjs.map} +0 -0
@@ -2,15 +2,22 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { type ChangeEvent, useCallback } from 'react';
5
+ import { Octokit } from '@octokit/core';
6
+ import React, { type ChangeEvent, useCallback, useEffect, useState } from 'react';
6
7
 
8
+ import { createIntent, SettingsAction, useIntentDispatcher } from '@dxos/app-framework';
9
+ import { FunctionType, type ScriptType, getInvocationUrl, getUserFunctionUrlInMetadata } from '@dxos/functions';
10
+ import { log } from '@dxos/log';
7
11
  import { useClient } from '@dxos/react-client';
8
12
  import { Filter, getMeta, getSpace, useQuery } from '@dxos/react-client/echo';
9
- import { Button, Icon, Input, useControlledValue, useTranslation } from '@dxos/react-ui';
13
+ import { Button, Clipboard, Input, Separator, useControlledValue, useTranslation } from '@dxos/react-ui';
14
+ import { AccessTokenType } from '@dxos/schema';
10
15
 
11
- import { getInvocationUrl, getUserFunctionUrlInMetadata } from '../edge';
12
16
  import { SCRIPT_PLUGIN } from '../meta';
13
- import { FunctionType, type ScriptType } from '../types';
17
+
18
+ // TODO(wittjosiah): Factor out.
19
+ // From https://stackoverflow.com/a/67243723/2804332
20
+ const kebabize = (str: string) => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? '-' : '') + $.toLowerCase());
14
21
 
15
22
  export type ScriptSettingsPanelProps = {
16
23
  script: ScriptType;
@@ -18,16 +25,37 @@ export type ScriptSettingsPanelProps = {
18
25
 
19
26
  export const ScriptSettingsPanel = ({ script }: ScriptSettingsPanelProps) => {
20
27
  const { t } = useTranslation(SCRIPT_PLUGIN);
28
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
21
29
  const client = useClient();
22
30
  const space = getSpace(script);
23
31
  const [fn] = useQuery(space, Filter.schema(FunctionType, { source: script }));
32
+ const [githubToken] = useQuery(space, Filter.schema(AccessTokenType, { source: 'github.com' }));
33
+ const gistKey = getMeta(script).keys.find(({ source }) => source === 'github.com');
34
+ const [gistUrl, setGistUrl] = useState<string | undefined>();
24
35
 
25
- const handleNameChange = useCallback(
26
- (event: ChangeEvent<HTMLInputElement>) => {
27
- script.name = event.target.value;
28
- },
29
- [script],
30
- );
36
+ useEffect(() => {
37
+ const token = githubToken?.token;
38
+ const gistId = gistKey?.id;
39
+ if (!token || !gistId) {
40
+ setGistUrl(undefined);
41
+ return;
42
+ }
43
+
44
+ const timeout = setTimeout(async () => {
45
+ try {
46
+ const octokit = new Octokit({ auth: githubToken.token });
47
+ const response = await octokit.request('GET /gists/{gist_id}', {
48
+ gist_id: gistId,
49
+ });
50
+ setGistUrl(response.data.html_url);
51
+ } catch (err) {
52
+ log.catch(err);
53
+ setGistUrl(undefined);
54
+ }
55
+ });
56
+
57
+ return () => clearTimeout(timeout);
58
+ }, [githubToken, gistKey]);
31
59
 
32
60
  const [binding, setBinding] = useControlledValue(fn?.binding ?? '');
33
61
  const handleBindingChange = useCallback(
@@ -47,55 +75,100 @@ export const ScriptSettingsPanel = ({ script }: ScriptSettingsPanelProps) => {
47
75
  spaceId: space?.id,
48
76
  });
49
77
 
50
- // TODO(wittjosiah): Use ClipboardProvider.
51
- const handleCopy = useCallback(() => functionUrl && navigator.clipboard.writeText(functionUrl), [functionUrl]);
78
+ const handleOpenTokenManager = useCallback(
79
+ () => dispatch(createIntent(SettingsAction.Open, { plugin: 'dxos.org/plugin/token-manager' })),
80
+ [],
81
+ );
82
+
83
+ const [publishing, setPublishing] = useState(false);
84
+ const handlePublish = useCallback(async () => {
85
+ setPublishing(true);
86
+ const octokit = new Octokit({ auth: githubToken.token });
87
+ const source = await script.source.load();
88
+ const filename = script.name ? kebabize(script.name) : 'composer-script';
89
+ const files = { [`${filename}.ts`]: { content: source.content } };
90
+
91
+ try {
92
+ // TODO(wittjosiah): Factor out to intent.
93
+ const meta = getMeta(script);
94
+ const githubKey = meta.keys.find(({ source }) => source === 'github.com');
95
+ const gistId = githubKey?.id;
96
+ if (gistId) {
97
+ await octokit.request('PATCH /gists/{gist_id}', {
98
+ gist_id: gistId,
99
+ files,
100
+ });
101
+ } else {
102
+ const response = await octokit.request('POST /gists', {
103
+ public: true,
104
+ files,
105
+ });
106
+ if (response.data.id) {
107
+ meta.keys.push({ source: 'github.com', id: response.data.id });
108
+ }
109
+ }
110
+ } finally {
111
+ setPublishing(false);
112
+ }
113
+ }, [script, githubToken]);
52
114
 
53
115
  return (
54
- <div role='form' className='flex flex-col w-full p-2 gap-4'>
55
- <Input.Root>
56
- <div role='none' className='flex flex-col gap-1'>
57
- <Input.Label>{t('name label')}</Input.Label>
58
- <Input.TextInput
59
- placeholder={t('object title placeholder')}
60
- value={script.name ?? ''}
61
- onChange={handleNameChange}
62
- />
63
- </div>
64
- </Input.Root>
65
- {fn && (
116
+ <>
117
+ {fn && functionUrl && (
66
118
  <>
67
- <hr className='border-separator' />
68
- <h2>{t('remote function settings heading')}</h2>
69
- <Input.Root>
70
- <div role='none' className='flex flex-col gap-1'>
71
- <Input.Label>{t('function url label')}</Input.Label>
72
- <div role='none' className='flex gap-1'>
119
+ <Separator />
120
+ <div role='form' className='flex flex-col w-full p-2 gap-4'>
121
+ <h2>{t('remote function settings heading')}</h2>
122
+ <Input.Root>
123
+ <div role='none' className='flex flex-col gap-1'>
124
+ <Input.Label>{t('function url label')}</Input.Label>
125
+ <div role='none' className='flex gap-1'>
126
+ <Input.TextInput
127
+ disabled
128
+ value={functionUrl}
129
+ onChange={(event) => {
130
+ fn.name = event.target.value;
131
+ }}
132
+ />
133
+ <Clipboard.IconButton value={functionUrl} />
134
+ </div>
135
+ </div>
136
+ </Input.Root>
137
+ <Input.Root>
138
+ <div role='none' className='flex flex-col gap-1'>
139
+ <Input.Label>{t('function binding label')}</Input.Label>
73
140
  <Input.TextInput
74
- disabled
75
- value={functionUrl}
76
- onChange={(event) => {
77
- fn.name = event.target.value;
78
- }}
141
+ placeholder={t('function binding placeholder')}
142
+ value={binding}
143
+ onChange={handleBindingChange}
144
+ onBlur={handleBindingBlur}
79
145
  />
80
- <Button onClick={handleCopy}>
81
- <Icon icon='ph--copy--regular' size={4} />
82
- </Button>
83
146
  </div>
84
- </div>
85
- </Input.Root>
86
- <Input.Root>
87
- <div role='none' className='flex flex-col gap-1'>
88
- <Input.Label>{t('function binding label')}</Input.Label>
89
- <Input.TextInput
90
- placeholder={t('function binding placeholder')}
91
- value={binding}
92
- onChange={handleBindingChange}
93
- onBlur={handleBindingBlur}
94
- />
95
- </div>
96
- </Input.Root>
147
+ </Input.Root>
148
+ </div>
97
149
  </>
98
150
  )}
99
- </div>
151
+ <Separator />
152
+ <div className='flex flex-col w-full p-2 gap-4'>
153
+ <div>
154
+ <h2>{t('script publish settings label')}</h2>
155
+ <p className='text-description text-sm'>{t('script publish settings description')}</p>
156
+ </div>
157
+ {!githubToken && (
158
+ <div className='flex flex-col items-center justify-center gap-2'>
159
+ <span>{t('no github token label')}</span>
160
+ <Button onClick={handleOpenTokenManager}>{t('open token manager label')}</Button>
161
+ </div>
162
+ )}
163
+ {githubToken && (
164
+ <div className='flex justify-end gap-2'>
165
+ {gistUrl && <Clipboard.IconButton value={gistUrl} />}
166
+ <Button disabled={publishing} onClick={handlePublish}>
167
+ {t(publishing ? 'publishing label' : 'publish label')}
168
+ </Button>
169
+ </div>
170
+ )}
171
+ </div>
172
+ </>
100
173
  );
101
174
  };
@@ -8,7 +8,7 @@ import { type Meta } from '@storybook/react';
8
8
 
9
9
  import { withLayout, withTheme } from '@dxos/storybook-utils';
10
10
 
11
- import { Toolbar } from './Toolbar';
11
+ import { ScriptToolbar } from './ScriptToolbar';
12
12
  import { templates } from '../../templates';
13
13
 
14
14
  export const Default = {
@@ -23,7 +23,7 @@ export const Default = {
23
23
 
24
24
  const meta: Meta = {
25
25
  title: 'plugins/plugin-script/Toolbar',
26
- component: Toolbar,
26
+ component: ScriptToolbar,
27
27
  decorators: [withTheme, withLayout({ tooltips: true })],
28
28
  };
29
29
 
@@ -0,0 +1,51 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback } from 'react';
6
+
7
+ import { type ScriptType } from '@dxos/functions';
8
+ import { fullyQualifiedId } from '@dxos/react-client/echo';
9
+ import { ElevationProvider, type ThemedClassName } from '@dxos/react-ui';
10
+ import { stackItemContentToolbarClassNames } from '@dxos/react-ui-editor';
11
+ import { createGapSeparator, MenuProvider, ToolbarMenu, useMenuActions } from '@dxos/react-ui-menu';
12
+
13
+ import { createDeploy } from './deploy';
14
+ import { createFormat } from './format';
15
+ import { createTemplateSelect } from './templateSelect';
16
+ import { useToolbarAction } from './useToolbarAction';
17
+ import { type ScriptToolbarState } from './useToolbarState';
18
+ import { createView } from './view';
19
+
20
+ export type ScriptToolbarProps = ThemedClassName<{
21
+ role?: string;
22
+ script: ScriptType;
23
+ state: ScriptToolbarState;
24
+ }>;
25
+
26
+ const createToolbar = (state: ScriptToolbarState) => {
27
+ const templateSelect = createTemplateSelect();
28
+ const format = createFormat();
29
+ const gap = createGapSeparator();
30
+ const deploy = createDeploy(state);
31
+ const view = createView(state);
32
+ return {
33
+ nodes: [...templateSelect.nodes, ...format.nodes, ...gap.nodes, ...deploy.nodes, ...view.nodes],
34
+ edges: [...templateSelect.edges, ...format.edges, ...gap.edges, ...deploy.edges, ...view.edges],
35
+ };
36
+ };
37
+
38
+ export const ScriptToolbar = ({ script, role, state, classNames }: ScriptToolbarProps) => {
39
+ const handleAction = useToolbarAction({ state, script });
40
+ const toolbarCreator = useCallback(() => createToolbar(state), [state]);
41
+ const menu = useMenuActions(toolbarCreator);
42
+ return (
43
+ <div role='none' className={stackItemContentToolbarClassNames(role)}>
44
+ <ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
45
+ <MenuProvider {...menu} onAction={handleAction} attendableId={fullyQualifiedId(script)}>
46
+ <ToolbarMenu classNames={classNames} />
47
+ </MenuProvider>
48
+ </ElevationProvider>
49
+ </div>
50
+ );
51
+ };
@@ -0,0 +1,157 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useCallback, useEffect, useMemo } from 'react';
6
+
7
+ import {
8
+ FunctionType,
9
+ getInvocationUrl,
10
+ getUserFunctionUrlInMetadata,
11
+ incrementSemverPatch,
12
+ type ScriptType,
13
+ setUserFunctionUrlInMetadata,
14
+ uploadWorkerFunction,
15
+ } from '@dxos/functions';
16
+ import { log } from '@dxos/log';
17
+ import { useClient } from '@dxos/react-client';
18
+ import { Filter, create, getMeta, getSpace, makeRef, useQuery } from '@dxos/react-client/echo';
19
+ import { useTranslation } from '@dxos/react-ui';
20
+ import { createMenuAction } from '@dxos/react-ui-menu';
21
+
22
+ import { type ViewState } from './view';
23
+ import { Bundler } from '../../bundler';
24
+ import { SCRIPT_PLUGIN } from '../../meta';
25
+
26
+ export type DeployActionProperties = { type: 'deploy' } | { type: 'copy' };
27
+
28
+ export type DeployState = ViewState & {
29
+ deploying: boolean;
30
+ deployed: boolean;
31
+ functionUrl: string;
32
+ error: string;
33
+ };
34
+
35
+ export const createDeploy = (state: Partial<DeployState>) => {
36
+ const errorItem = createMenuAction('error', {
37
+ label: state.error ?? ['no error label', { ns: SCRIPT_PLUGIN }],
38
+ icon: 'ph--warning-circle--regular',
39
+ hidden: !state.error,
40
+ });
41
+
42
+ const deployAction = createMenuAction<DeployActionProperties>('deploy', {
43
+ type: 'deploy',
44
+ label: [state.deploying ? 'pending label' : 'deploy label', { ns: SCRIPT_PLUGIN }],
45
+ icon: state.deploying ? 'ph--spinner-gap--regular' : 'ph--cloud-arrow-up--regular',
46
+ disabled: state.deploying,
47
+ classNames: state.deploying ? '[&_svg]:animate-spin' : '',
48
+ });
49
+
50
+ const copyAction = createMenuAction<DeployActionProperties>('copy', {
51
+ type: 'copy',
52
+ label: ['copy link label', { ns: SCRIPT_PLUGIN }],
53
+ icon: 'ph--link--regular',
54
+ disabled: !state.functionUrl,
55
+ });
56
+
57
+ return {
58
+ nodes: [errorItem, deployAction, copyAction],
59
+ edges: [
60
+ { source: 'root', target: 'error' },
61
+ { source: 'root', target: 'deploy' },
62
+ { source: 'root', target: 'copy' },
63
+ ],
64
+ };
65
+ };
66
+
67
+ const useDeployDeps = ({ state, script }: { state: Partial<DeployState>; script: ScriptType }) => {
68
+ const space = getSpace(script);
69
+ const [fn] = useQuery(space, Filter.schema(FunctionType, { source: script }));
70
+ const client = useClient();
71
+ const existingFunctionUrl = useMemo(() => fn && getUserFunctionUrlInMetadata(getMeta(fn)), [fn]);
72
+ return { space, fn, client, existingFunctionUrl };
73
+ };
74
+
75
+ export const useDeployState = ({ state, script }: { state: Partial<DeployState>; script: ScriptType }) => {
76
+ const { space, client, existingFunctionUrl } = useDeployDeps({ state, script });
77
+ useEffect(() => {
78
+ if (!existingFunctionUrl) {
79
+ return;
80
+ }
81
+
82
+ state.functionUrl = getInvocationUrl(existingFunctionUrl, client.config.values.runtime?.services?.edge?.url ?? '', {
83
+ spaceId: space?.id,
84
+ });
85
+ }, [existingFunctionUrl, space]);
86
+
87
+ useEffect(() => {
88
+ state.deployed = Boolean(existingFunctionUrl) && !script.changed;
89
+ }, [script.changed, existingFunctionUrl]);
90
+ };
91
+
92
+ export const useDeployHandler = ({ state, script }: { state: Partial<DeployState>; script: ScriptType }) => {
93
+ const { space, fn, client, existingFunctionUrl } = useDeployDeps({ state, script });
94
+ const { t } = useTranslation(SCRIPT_PLUGIN);
95
+
96
+ return useCallback(async () => {
97
+ if (!script.source || !space) {
98
+ return;
99
+ }
100
+
101
+ state.error = undefined;
102
+ state.deploying = true;
103
+
104
+ try {
105
+ const existingFunctionId = existingFunctionUrl?.split('/').at(-1);
106
+
107
+ const bundler = new Bundler({ platform: 'browser', sandboxedModules: [], remoteModules: {} });
108
+ const buildResult = await bundler.bundle(script.source.target!.content);
109
+ if (buildResult.error || !buildResult.bundle) {
110
+ throw buildResult.error;
111
+ }
112
+
113
+ const { functionId, version, meta } = await uploadWorkerFunction({
114
+ client,
115
+ spaceId: space.id,
116
+ version: fn ? incrementSemverPatch(fn.version) : '0.0.1',
117
+ functionId: existingFunctionId,
118
+ source: buildResult.bundle,
119
+ });
120
+ if (functionId === undefined || version === undefined) {
121
+ throw new Error(`Upload didn't return expected data: functionId=${functionId}, version=${version}`);
122
+ }
123
+
124
+ log.info('function uploaded', { functionId, version });
125
+ if (fn) {
126
+ fn.version = version;
127
+ }
128
+
129
+ const deployedFunction =
130
+ fn ?? space.db.add(create(FunctionType, { name: functionId, version, source: makeRef(script) }));
131
+
132
+ script.changed = false;
133
+
134
+ if (meta.inputSchema) {
135
+ deployedFunction.inputSchema = meta.inputSchema;
136
+ } else {
137
+ log.verbose('no input schema in function metadata', { functionId });
138
+ }
139
+
140
+ setUserFunctionUrlInMetadata(getMeta(deployedFunction), `/${space.id}/${functionId}`);
141
+
142
+ state.view = 'split';
143
+ } catch (err: any) {
144
+ log.catch(err);
145
+ state.error = t('upload failed label');
146
+ }
147
+ state.deploying = false;
148
+ }, [fn, client, t, existingFunctionUrl, script, script.name, script.source, space?.id ?? null]);
149
+ };
150
+
151
+ export const useCopyHandler = ({ state }: { state: Partial<DeployState> }) =>
152
+ useCallback(async () => {
153
+ if (!state.functionUrl) {
154
+ return;
155
+ }
156
+ await navigator.clipboard.writeText(state.functionUrl);
157
+ }, [state.functionUrl]);
@@ -0,0 +1,47 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { format } from 'prettier';
6
+ import prettierPluginEstree from 'prettier/plugins/estree';
7
+ import prettierPluginTypescript from 'prettier/plugins/typescript';
8
+ import { useCallback } from 'react';
9
+
10
+ import { type ScriptType } from '@dxos/functions';
11
+ import { log } from '@dxos/log';
12
+ import { createMenuAction } from '@dxos/react-ui-menu';
13
+
14
+ import { SCRIPT_PLUGIN } from '../../meta';
15
+
16
+ export type FormatActionProperties = { type: 'format' };
17
+
18
+ export const createFormat = () => {
19
+ const formatAction = createMenuAction('format', {
20
+ label: ['format label', { ns: SCRIPT_PLUGIN }],
21
+ icon: 'ph--magic-wand--regular',
22
+ });
23
+
24
+ return {
25
+ nodes: [formatAction],
26
+ edges: [{ source: 'root', target: 'format' }],
27
+ };
28
+ };
29
+
30
+ export const useFormatHandler = ({ script }: { script: ScriptType }) =>
31
+ useCallback(async () => {
32
+ if (!script.source) {
33
+ return;
34
+ }
35
+
36
+ try {
37
+ script.source.target!.content = await format(script.source.target!.content, {
38
+ parser: 'typescript',
39
+ plugins: [prettierPluginEstree, prettierPluginTypescript],
40
+ semi: true,
41
+ singleQuote: true,
42
+ });
43
+ } catch (err: any) {
44
+ // TODO(wittjosiah): Show error in UI.
45
+ log.catch(err);
46
+ }
47
+ }, [script.source]);
@@ -2,4 +2,4 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export * from './Toolbar';
5
+ export * from './ScriptToolbar';
@@ -0,0 +1,64 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useCallback } from 'react';
6
+
7
+ import { FUNCTIONS_PRESET_META_KEY, type ScriptType } from '@dxos/functions';
8
+ import { getMeta } from '@dxos/live-object';
9
+ import { createMenuItemGroup, createMenuAction } from '@dxos/react-ui-menu';
10
+
11
+ import { SCRIPT_PLUGIN } from '../../meta';
12
+ import { templates } from '../../templates';
13
+
14
+ export type TemplateActionProperties = { type: 'template'; value: string };
15
+
16
+ const createTemplateSelectGroup = () => {
17
+ return createMenuItemGroup('template-select', {
18
+ label: ['template select group label', { ns: SCRIPT_PLUGIN }],
19
+ variant: 'dropdownMenu',
20
+ });
21
+ };
22
+
23
+ const createTemplateSelectActions = () => {
24
+ return templates.map((template) => {
25
+ return createMenuAction<TemplateActionProperties>(`template--${template.id}`, {
26
+ label: template.name,
27
+ value: template.id,
28
+ type: 'template',
29
+ });
30
+ });
31
+ };
32
+
33
+ export const createTemplateSelect = () => {
34
+ const templateSelectGroup = createTemplateSelectGroup();
35
+ const templateSelectActions = createTemplateSelectActions();
36
+ return {
37
+ nodes: [templateSelectGroup, ...templateSelectActions],
38
+ edges: [
39
+ { source: 'root', target: 'template-select' },
40
+ ...templateSelectActions.map((action) => ({ source: 'template-select', target: action.id })),
41
+ ],
42
+ };
43
+ };
44
+
45
+ export const useTemplateSelectHandler = ({ script }: { script: ScriptType }) => {
46
+ return useCallback(
47
+ (templateId: string) => {
48
+ const template = templates.find((template) => template.id === templateId);
49
+ if (template) {
50
+ script.name = template.name;
51
+ script.source!.target!.content = template.source;
52
+ const metaKeys = getMeta(script).keys;
53
+ const oldPresetIndex = metaKeys.findIndex((key) => key.source === FUNCTIONS_PRESET_META_KEY);
54
+ if (oldPresetIndex >= 0) {
55
+ metaKeys.splice(oldPresetIndex, 1);
56
+ }
57
+ if (template.presetId) {
58
+ metaKeys.push({ source: FUNCTIONS_PRESET_META_KEY, id: template.presetId });
59
+ }
60
+ }
61
+ },
62
+ [script],
63
+ );
64
+ };
@@ -0,0 +1,54 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useCallback } from 'react';
6
+
7
+ import { type ScriptType } from '@dxos/functions';
8
+ import { log } from '@dxos/log';
9
+ import { type MenuAction, type MenuActionHandler } from '@dxos/react-ui-menu';
10
+
11
+ import { type DeployActionProperties, useDeployHandler, useCopyHandler } from './deploy';
12
+ import { type FormatActionProperties, useFormatHandler } from './format';
13
+ import { type TemplateActionProperties, useTemplateSelectHandler } from './templateSelect';
14
+ import { type ScriptToolbarState } from './useToolbarState';
15
+ import { type ViewActionProperties } from './view';
16
+
17
+ export type ScriptToolbarActionProperties =
18
+ | TemplateActionProperties
19
+ | ViewActionProperties
20
+ | FormatActionProperties
21
+ | DeployActionProperties;
22
+
23
+ export type ScriptToolbarAction = MenuAction<ScriptToolbarActionProperties>;
24
+
25
+ export const useToolbarAction = (props: { state: ScriptToolbarState; script: ScriptType }) => {
26
+ const handleTemplateSelect = useTemplateSelectHandler(props);
27
+ const handleFormat = useFormatHandler(props);
28
+ const handleDeploy = useDeployHandler(props);
29
+ const handleCopy = useCopyHandler(props);
30
+ return useCallback(
31
+ ((action: ScriptToolbarAction) => {
32
+ switch (action.properties.type) {
33
+ case 'template':
34
+ handleTemplateSelect(action.properties.value);
35
+ break;
36
+ case 'view':
37
+ props.state.view = action.properties.value;
38
+ break;
39
+ case 'format':
40
+ void handleFormat();
41
+ break;
42
+ case 'deploy':
43
+ void handleDeploy();
44
+ break;
45
+ case 'copy':
46
+ void handleCopy();
47
+ break;
48
+ default:
49
+ log.error('Unknown action type', action);
50
+ }
51
+ }) as MenuActionHandler,
52
+ [handleTemplateSelect, handleFormat, handleDeploy, handleCopy],
53
+ );
54
+ };
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useMemo } from 'react';
6
+
7
+ import { create } from '@dxos/live-object';
8
+
9
+ import { type DeployState } from './deploy';
10
+ import { type ViewState } from './view';
11
+
12
+ export type ScriptToolbarState = Partial<DeployState & ViewState>;
13
+
14
+ export const useToolbarState = (initialState: ScriptToolbarState = {}) => {
15
+ return useMemo(() => create<ScriptToolbarState>(initialState), []);
16
+ };
@@ -0,0 +1,52 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { createMenuAction, createMenuItemGroup } from '@dxos/react-ui-menu';
6
+
7
+ import { SCRIPT_PLUGIN } from '../../meta';
8
+
9
+ export type ViewType = 'editor' | 'split' | 'debug';
10
+
11
+ export type ViewState = { view: ViewType };
12
+
13
+ export type ViewActionProperties = { type: 'view'; value: ViewType };
14
+
15
+ const views: Record<ViewType, string> = {
16
+ editor: 'ph--code--regular',
17
+ split: 'ph--square-split-vertical--regular',
18
+ debug: 'ph--bug--regular',
19
+ };
20
+
21
+ const createViewGroupItem = (state: Partial<ViewState>) => {
22
+ return createMenuItemGroup('view', {
23
+ label: ['view group label', { ns: SCRIPT_PLUGIN }],
24
+ variant: 'dropdownMenu',
25
+ applyActive: true,
26
+ value: state.view,
27
+ });
28
+ };
29
+
30
+ const createViewActions = (state: Partial<ViewState>) => {
31
+ return Object.entries(views).map(([viewType, icon]) => {
32
+ return createMenuAction<ViewActionProperties>(`view--${viewType}`, {
33
+ type: 'view',
34
+ value: viewType as ViewType,
35
+ label: [`view ${viewType} label`, { ns: SCRIPT_PLUGIN }],
36
+ icon,
37
+ checked: state.view === viewType,
38
+ });
39
+ });
40
+ };
41
+
42
+ export const createView = (state: Partial<ViewState>) => {
43
+ const viewGroupItem = createViewGroupItem(state);
44
+ const viewActions = createViewActions(state);
45
+ return {
46
+ nodes: [viewGroupItem, ...viewActions],
47
+ edges: [
48
+ { source: 'root', target: 'view' },
49
+ ...viewActions.map((action) => ({ source: 'view', target: action.id })),
50
+ ],
51
+ };
52
+ };