@dxos/plugin-script 0.8.4-main.dedc0f3 → 0.8.4-main.ead640a

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 (253) hide show
  1. package/dist/lib/browser/DeploymentDialog-65TWT6S5.mjs +13 -0
  2. package/dist/lib/browser/NotebookContainer-LVGRPFY3.mjs +683 -0
  3. package/dist/lib/browser/NotebookContainer-LVGRPFY3.mjs.map +7 -0
  4. package/dist/lib/browser/ScriptContainer-LRTRN7JW.mjs +149 -0
  5. package/dist/lib/browser/ScriptContainer-LRTRN7JW.mjs.map +7 -0
  6. package/dist/lib/browser/{app-graph-builder-IABOSTBK.mjs → app-graph-builder-DPYULSME.mjs} +8 -7
  7. package/dist/lib/browser/app-graph-builder-DPYULSME.mjs.map +7 -0
  8. package/dist/lib/browser/{blueprint-definition-AR7ITBCD.mjs → blueprint-definition-ET5KZ46I.mjs} +3 -3
  9. package/dist/lib/browser/{blueprint-definition-AR7ITBCD.mjs.map → blueprint-definition-ET5KZ46I.mjs.map} +1 -1
  10. package/dist/lib/browser/chunk-5CYLWXRH.mjs +89 -0
  11. package/dist/lib/browser/chunk-5CYLWXRH.mjs.map +7 -0
  12. package/dist/lib/browser/chunk-75LH4EUR.mjs +326 -0
  13. package/dist/lib/browser/chunk-75LH4EUR.mjs.map +7 -0
  14. package/dist/lib/browser/{chunk-6CAH7VIE.mjs → chunk-E7DXDICD.mjs} +18 -19
  15. package/dist/lib/browser/chunk-E7DXDICD.mjs.map +7 -0
  16. package/dist/lib/browser/{chunk-QYAREHGH.mjs → chunk-EZVXV6DA.mjs} +3 -5
  17. package/dist/lib/browser/chunk-EZVXV6DA.mjs.map +7 -0
  18. package/dist/lib/browser/{chunk-GZKWMME3.mjs → chunk-I3QSGUFJ.mjs} +122 -32
  19. package/dist/lib/browser/chunk-I3QSGUFJ.mjs.map +7 -0
  20. package/dist/lib/browser/{chunk-NXKU3BNX.mjs → chunk-JO2O7W6J.mjs} +39 -7
  21. package/dist/lib/browser/chunk-JO2O7W6J.mjs.map +7 -0
  22. package/dist/lib/browser/chunk-N6M34EUC.mjs +112 -0
  23. package/dist/lib/browser/chunk-N6M34EUC.mjs.map +7 -0
  24. package/dist/lib/browser/{chunk-YCZPTTFO.mjs → chunk-NM4WQS4F.mjs} +14 -14
  25. package/dist/lib/browser/chunk-NM4WQS4F.mjs.map +7 -0
  26. package/dist/lib/browser/{chunk-5TVBECWH.mjs → chunk-OKXN2N7M.mjs} +2 -2
  27. package/dist/lib/browser/chunk-ST3ACVUC.mjs +88 -0
  28. package/dist/lib/browser/chunk-ST3ACVUC.mjs.map +7 -0
  29. package/dist/lib/browser/{compiler-2HJH34GM.mjs → compiler-G2N2CG63.mjs} +5 -5
  30. package/dist/lib/browser/{compiler-2HJH34GM.mjs.map → compiler-G2N2CG63.mjs.map} +1 -1
  31. package/dist/lib/browser/index.mjs +107 -36
  32. package/dist/lib/browser/index.mjs.map +3 -3
  33. package/dist/lib/browser/{intent-resolver-F4YSRPJI.mjs → intent-resolver-JLU7DVLQ.mjs} +31 -15
  34. package/dist/lib/browser/intent-resolver-JLU7DVLQ.mjs.map +7 -0
  35. package/dist/lib/browser/meta.json +1 -1
  36. package/dist/lib/browser/{react-surface-BBHFU6MI.mjs → react-surface-76SDTUYG.mjs} +36 -13
  37. package/dist/lib/browser/react-surface-76SDTUYG.mjs.map +7 -0
  38. package/dist/lib/browser/{settings-KCTBK5TY.mjs → settings-ERFKVNUK.mjs} +9 -8
  39. package/dist/lib/browser/settings-ERFKVNUK.mjs.map +7 -0
  40. package/dist/lib/browser/templates/index.mjs +1 -1
  41. package/dist/lib/browser/types/index.mjs +7 -4
  42. package/dist/lib/node-esm/{DeploymentDialog-G6EHEPXN.mjs → DeploymentDialog-I63ZC2HH.mjs} +6 -5
  43. package/dist/lib/node-esm/NotebookContainer-QY5NJGJI.mjs +684 -0
  44. package/dist/lib/node-esm/NotebookContainer-QY5NJGJI.mjs.map +7 -0
  45. package/dist/lib/node-esm/ScriptContainer-SVXCSLNH.mjs +150 -0
  46. package/dist/lib/node-esm/ScriptContainer-SVXCSLNH.mjs.map +7 -0
  47. package/dist/lib/node-esm/{app-graph-builder-CQTTAYHP.mjs → app-graph-builder-UXJGHXSL.mjs} +8 -7
  48. package/dist/lib/node-esm/app-graph-builder-UXJGHXSL.mjs.map +7 -0
  49. package/dist/lib/node-esm/{blueprint-definition-TJY4TX6S.mjs → blueprint-definition-AIYFOT7Q.mjs} +3 -3
  50. package/dist/lib/node-esm/{blueprint-definition-TJY4TX6S.mjs.map → blueprint-definition-AIYFOT7Q.mjs.map} +1 -1
  51. package/dist/lib/node-esm/chunk-2GVTWESW.mjs +90 -0
  52. package/dist/lib/node-esm/chunk-2GVTWESW.mjs.map +7 -0
  53. package/dist/lib/node-esm/chunk-4X375PGY.mjs +90 -0
  54. package/dist/lib/node-esm/chunk-4X375PGY.mjs.map +7 -0
  55. package/dist/lib/node-esm/chunk-67OVZHI3.mjs +327 -0
  56. package/dist/lib/node-esm/chunk-67OVZHI3.mjs.map +7 -0
  57. package/dist/lib/node-esm/{chunk-ZA36GO4T.mjs → chunk-C2ORIPKH.mjs} +14 -14
  58. package/dist/lib/node-esm/chunk-C2ORIPKH.mjs.map +7 -0
  59. package/dist/lib/node-esm/{chunk-35M3CHYE.mjs → chunk-NUXZQQ6P.mjs} +2 -2
  60. package/dist/lib/node-esm/{chunk-AHXJ6NQU.mjs → chunk-OG2SIKHE.mjs} +3 -5
  61. package/dist/lib/node-esm/chunk-OG2SIKHE.mjs.map +7 -0
  62. package/dist/lib/node-esm/{chunk-HUHVIOL5.mjs → chunk-SMFPSKQT.mjs} +122 -32
  63. package/dist/lib/node-esm/chunk-SMFPSKQT.mjs.map +7 -0
  64. package/dist/lib/node-esm/chunk-VRSDE4CI.mjs +114 -0
  65. package/dist/lib/node-esm/chunk-VRSDE4CI.mjs.map +7 -0
  66. package/dist/lib/node-esm/{chunk-2GBESIHU.mjs → chunk-VZAFGLD7.mjs} +18 -19
  67. package/dist/lib/node-esm/chunk-VZAFGLD7.mjs.map +7 -0
  68. package/dist/lib/node-esm/{chunk-M642JUOZ.mjs → chunk-YW36TZ7K.mjs} +39 -7
  69. package/dist/lib/node-esm/chunk-YW36TZ7K.mjs.map +7 -0
  70. package/dist/lib/node-esm/{compiler-7SP27RA6.mjs → compiler-PLDAZ5GJ.mjs} +5 -5
  71. package/dist/lib/node-esm/{compiler-7SP27RA6.mjs.map → compiler-PLDAZ5GJ.mjs.map} +1 -1
  72. package/dist/lib/node-esm/index.mjs +107 -36
  73. package/dist/lib/node-esm/index.mjs.map +3 -3
  74. package/dist/lib/node-esm/{intent-resolver-CGQYRWWD.mjs → intent-resolver-SFGTIFOG.mjs} +31 -15
  75. package/dist/lib/node-esm/intent-resolver-SFGTIFOG.mjs.map +7 -0
  76. package/dist/lib/node-esm/meta.json +1 -1
  77. package/dist/lib/node-esm/{react-surface-UWIWPKZD.mjs → react-surface-SHEBNW4R.mjs} +36 -13
  78. package/dist/lib/node-esm/react-surface-SHEBNW4R.mjs.map +7 -0
  79. package/dist/lib/node-esm/{settings-DXZ334A3.mjs → settings-5TYXQ42N.mjs} +9 -8
  80. package/dist/lib/node-esm/settings-5TYXQ42N.mjs.map +7 -0
  81. package/dist/lib/node-esm/templates/index.mjs +1 -1
  82. package/dist/lib/node-esm/types/index.mjs +7 -4
  83. package/dist/types/src/ScriptPlugin.d.ts +1 -1
  84. package/dist/types/src/ScriptPlugin.d.ts.map +1 -1
  85. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  86. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  87. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  88. package/dist/types/src/components/DeploymentDialog/DeploymentDialog.d.ts +1 -1
  89. package/dist/types/src/components/DeploymentDialog/DeploymentDialog.d.ts.map +1 -1
  90. package/dist/types/src/components/DeploymentDialog/DeploymentDialog.stories.d.ts +111 -5
  91. package/dist/types/src/components/DeploymentDialog/DeploymentDialog.stories.d.ts.map +1 -1
  92. package/dist/types/src/components/NotebookContainer.d.ts +10 -0
  93. package/dist/types/src/components/NotebookContainer.d.ts.map +1 -0
  94. package/dist/types/src/components/NotebookContainer.stories.d.ts +248 -0
  95. package/dist/types/src/components/NotebookContainer.stories.d.ts.map +1 -0
  96. package/dist/types/src/components/NotebookStack/NotebookCell.d.ts +14 -0
  97. package/dist/types/src/components/NotebookStack/NotebookCell.d.ts.map +1 -0
  98. package/dist/types/src/components/NotebookStack/NotebookMenu.d.ts +9 -0
  99. package/dist/types/src/components/NotebookStack/NotebookMenu.d.ts.map +1 -0
  100. package/dist/types/src/components/NotebookStack/NotebookStack.d.ts +14 -0
  101. package/dist/types/src/components/NotebookStack/NotebookStack.d.ts.map +1 -0
  102. package/dist/types/src/components/NotebookStack/NotebookStack.stories.d.ts +248 -0
  103. package/dist/types/src/components/NotebookStack/NotebookStack.stories.d.ts.map +1 -0
  104. package/dist/types/src/components/NotebookStack/index.d.ts +3 -0
  105. package/dist/types/src/components/NotebookStack/index.d.ts.map +1 -0
  106. package/dist/types/src/components/ScriptContainer.d.ts +2 -2
  107. package/dist/types/src/components/ScriptContainer.d.ts.map +1 -1
  108. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.d.ts.map +1 -1
  109. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.stories.d.ts +239 -1
  110. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.stories.d.ts.map +1 -1
  111. package/dist/types/src/components/Settings/ScriptObjectSettings.d.ts.map +1 -1
  112. package/dist/types/src/components/Settings/ScriptPluginSettings.d.ts +2 -2
  113. package/dist/types/src/components/Settings/ScriptPluginSettings.d.ts.map +1 -1
  114. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.d.ts +4 -2
  115. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.d.ts.map +1 -1
  116. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.stories.d.ts +3 -3
  117. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.stories.d.ts.map +1 -1
  118. package/dist/types/src/components/index.d.ts +2 -0
  119. package/dist/types/src/components/index.d.ts.map +1 -1
  120. package/dist/types/src/events.d.ts.map +1 -1
  121. package/dist/types/src/hooks/deploy.d.ts +6 -6
  122. package/dist/types/src/hooks/deploy.d.ts.map +1 -1
  123. package/dist/types/src/hooks/template.d.ts.map +1 -1
  124. package/dist/types/src/index.d.ts +1 -0
  125. package/dist/types/src/index.d.ts.map +1 -1
  126. package/dist/types/src/meta.d.ts +0 -1
  127. package/dist/types/src/meta.d.ts.map +1 -1
  128. package/dist/types/src/notebook/eval.d.ts +13 -0
  129. package/dist/types/src/notebook/eval.d.ts.map +1 -0
  130. package/dist/types/src/notebook/index.d.ts +2 -0
  131. package/dist/types/src/notebook/index.d.ts.map +1 -0
  132. package/dist/types/src/notebook/notebook.d.ts +35 -0
  133. package/dist/types/src/notebook/notebook.d.ts.map +1 -0
  134. package/dist/types/src/notebook/notebook.test.d.ts +2 -0
  135. package/dist/types/src/notebook/notebook.test.d.ts.map +1 -0
  136. package/dist/types/src/notebook/vfs-parser.d.ts +74 -0
  137. package/dist/types/src/notebook/vfs-parser.d.ts.map +1 -0
  138. package/dist/types/src/notebook/vfs-parser.test.d.ts +2 -0
  139. package/dist/types/src/notebook/vfs-parser.test.d.ts.map +1 -0
  140. package/dist/types/src/templates/chess.d.ts.map +1 -1
  141. package/dist/types/src/templates/data-generator.d.ts.map +1 -1
  142. package/dist/types/src/templates/discord.d.ts.map +1 -1
  143. package/dist/types/src/templates/forex-effect.d.ts.map +1 -1
  144. package/dist/types/src/templates/forex.d.ts.map +1 -1
  145. package/dist/types/src/templates/gmail.d.ts.map +1 -1
  146. package/dist/types/src/templates/index.d.ts +43 -1
  147. package/dist/types/src/templates/index.d.ts.map +1 -1
  148. package/dist/types/src/templates/{echo.d.ts → ping.d.ts} +1 -1
  149. package/dist/types/src/templates/ping.d.ts.map +1 -0
  150. package/dist/types/src/testing/data.d.ts +19 -0
  151. package/dist/types/src/testing/data.d.ts.map +1 -0
  152. package/dist/types/src/testing/index.d.ts +2 -0
  153. package/dist/types/src/testing/index.d.ts.map +1 -0
  154. package/dist/types/src/translations.d.ts +27 -2
  155. package/dist/types/src/translations.d.ts.map +1 -1
  156. package/dist/types/src/types/actions.d.ts +66 -0
  157. package/dist/types/src/types/actions.d.ts.map +1 -0
  158. package/dist/types/src/types/index.d.ts +1 -0
  159. package/dist/types/src/types/index.d.ts.map +1 -1
  160. package/dist/types/src/types/schema.d.ts +54 -31
  161. package/dist/types/src/types/schema.d.ts.map +1 -1
  162. package/dist/types/src/util/functions.d.ts +5 -2
  163. package/dist/types/src/util/functions.d.ts.map +1 -1
  164. package/dist/types/tsconfig.tsbuildinfo +1 -1
  165. package/package.json +67 -63
  166. package/src/ScriptPlugin.tsx +93 -68
  167. package/src/capabilities/app-graph-builder.ts +4 -3
  168. package/src/capabilities/artifact-definition.ts +1 -1
  169. package/src/capabilities/intent-resolver.ts +14 -4
  170. package/src/capabilities/react-surface.tsx +17 -5
  171. package/src/capabilities/settings.ts +3 -3
  172. package/src/components/DeploymentDialog/DeploymentDialog.stories.tsx +6 -4
  173. package/src/components/DeploymentDialog/DeploymentDialog.tsx +11 -17
  174. package/src/components/NotebookContainer.stories.tsx +32 -0
  175. package/src/components/NotebookContainer.tsx +124 -0
  176. package/src/components/NotebookStack/NotebookCell.tsx +217 -0
  177. package/src/components/NotebookStack/NotebookMenu.tsx +47 -0
  178. package/src/components/NotebookStack/NotebookStack.stories.tsx +32 -0
  179. package/src/components/NotebookStack/NotebookStack.tsx +79 -0
  180. package/src/components/NotebookStack/index.ts +6 -0
  181. package/src/components/ScriptContainer.tsx +2 -2
  182. package/src/components/ScriptToolbar/ScriptToolbar.stories.tsx +17 -5
  183. package/src/components/ScriptToolbar/ScriptToolbar.tsx +21 -24
  184. package/src/components/Settings/ScriptObjectSettings.tsx +92 -8
  185. package/src/components/Settings/ScriptPluginSettings.tsx +4 -19
  186. package/src/components/TestPanel/TestPanel.tsx +5 -5
  187. package/src/components/TypescriptEditor/TypescriptEditor.stories.tsx +71 -16
  188. package/src/components/TypescriptEditor/TypescriptEditor.tsx +29 -24
  189. package/src/components/index.ts +3 -0
  190. package/src/events.ts +2 -2
  191. package/src/hooks/deploy.ts +8 -9
  192. package/src/hooks/format.ts +2 -2
  193. package/src/hooks/template.ts +4 -3
  194. package/src/hooks/useCreateAndDeployScriptTemplates.ts +3 -3
  195. package/src/index.ts +1 -0
  196. package/src/meta.ts +2 -4
  197. package/src/notebook/eval.ts +105 -0
  198. package/src/notebook/index.ts +5 -0
  199. package/src/notebook/notebook.test.ts +70 -0
  200. package/src/notebook/notebook.ts +183 -0
  201. package/src/notebook/vfs-parser.test.ts +149 -0
  202. package/src/notebook/vfs-parser.ts +451 -0
  203. package/src/templates/chess.ts +2 -0
  204. package/src/templates/data-generator.ts +2 -0
  205. package/src/templates/discord.ts +9 -1
  206. package/src/templates/forex-effect.ts +5 -1
  207. package/src/templates/forex.ts +2 -0
  208. package/src/templates/gmail.ts +21 -9
  209. package/src/templates/index.ts +6 -6
  210. package/src/testing/data.ts +47 -0
  211. package/src/testing/index.ts +5 -0
  212. package/src/translations.ts +30 -4
  213. package/src/types/actions.ts +53 -0
  214. package/src/types/index.ts +1 -0
  215. package/src/types/schema.ts +30 -19
  216. package/src/util/functions.ts +32 -3
  217. package/dist/lib/browser/DeploymentDialog-QZSTVNIS.mjs +0 -12
  218. package/dist/lib/browser/ScriptContainer-DNNA6XC6.mjs +0 -265
  219. package/dist/lib/browser/ScriptContainer-DNNA6XC6.mjs.map +0 -7
  220. package/dist/lib/browser/app-graph-builder-IABOSTBK.mjs.map +0 -7
  221. package/dist/lib/browser/chunk-6CAH7VIE.mjs.map +0 -7
  222. package/dist/lib/browser/chunk-GZKWMME3.mjs.map +0 -7
  223. package/dist/lib/browser/chunk-IS4OG2UW.mjs +0 -39
  224. package/dist/lib/browser/chunk-IS4OG2UW.mjs.map +0 -7
  225. package/dist/lib/browser/chunk-NXKU3BNX.mjs.map +0 -7
  226. package/dist/lib/browser/chunk-QYAREHGH.mjs.map +0 -7
  227. package/dist/lib/browser/chunk-RNGIQIEJ.mjs +0 -88
  228. package/dist/lib/browser/chunk-RNGIQIEJ.mjs.map +0 -7
  229. package/dist/lib/browser/chunk-YCZPTTFO.mjs.map +0 -7
  230. package/dist/lib/browser/intent-resolver-F4YSRPJI.mjs.map +0 -7
  231. package/dist/lib/browser/react-surface-BBHFU6MI.mjs.map +0 -7
  232. package/dist/lib/browser/settings-KCTBK5TY.mjs.map +0 -7
  233. package/dist/lib/node-esm/ScriptContainer-KPYZN2KY.mjs +0 -266
  234. package/dist/lib/node-esm/ScriptContainer-KPYZN2KY.mjs.map +0 -7
  235. package/dist/lib/node-esm/app-graph-builder-CQTTAYHP.mjs.map +0 -7
  236. package/dist/lib/node-esm/chunk-2GBESIHU.mjs.map +0 -7
  237. package/dist/lib/node-esm/chunk-AHXJ6NQU.mjs.map +0 -7
  238. package/dist/lib/node-esm/chunk-GWHLP5LM.mjs +0 -90
  239. package/dist/lib/node-esm/chunk-GWHLP5LM.mjs.map +0 -7
  240. package/dist/lib/node-esm/chunk-HUHVIOL5.mjs.map +0 -7
  241. package/dist/lib/node-esm/chunk-JIPFLBYA.mjs +0 -40
  242. package/dist/lib/node-esm/chunk-JIPFLBYA.mjs.map +0 -7
  243. package/dist/lib/node-esm/chunk-M642JUOZ.mjs.map +0 -7
  244. package/dist/lib/node-esm/chunk-ZA36GO4T.mjs.map +0 -7
  245. package/dist/lib/node-esm/intent-resolver-CGQYRWWD.mjs.map +0 -7
  246. package/dist/lib/node-esm/react-surface-UWIWPKZD.mjs.map +0 -7
  247. package/dist/lib/node-esm/settings-DXZ334A3.mjs.map +0 -7
  248. package/dist/types/src/templates/echo.d.ts.map +0 -1
  249. /package/dist/lib/browser/{DeploymentDialog-QZSTVNIS.mjs.map → DeploymentDialog-65TWT6S5.mjs.map} +0 -0
  250. /package/dist/lib/browser/{chunk-5TVBECWH.mjs.map → chunk-OKXN2N7M.mjs.map} +0 -0
  251. /package/dist/lib/node-esm/{DeploymentDialog-G6EHEPXN.mjs.map → DeploymentDialog-I63ZC2HH.mjs.map} +0 -0
  252. /package/dist/lib/node-esm/{chunk-35M3CHYE.mjs.map → chunk-NUXZQQ6P.mjs.map} +0 -0
  253. /package/src/templates/{echo.ts → ping.ts} +0 -0
@@ -0,0 +1,124 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo } from 'react';
6
+
7
+ import { Ref } from '@dxos/echo';
8
+ import { invariant } from '@dxos/invariant';
9
+ import { Assistant } from '@dxos/plugin-assistant';
10
+ import { getSpace } from '@dxos/react-client/echo';
11
+ import { DropdownMenu, IconButton, Toolbar, useTranslation } from '@dxos/react-ui';
12
+ import { StackItem } from '@dxos/react-ui-stack';
13
+ import { DataType } from '@dxos/schema';
14
+
15
+ import { meta } from '../meta';
16
+ import { ComputeGraph } from '../notebook';
17
+ import { type Notebook } from '../types';
18
+
19
+ import { NotebookMenu, NotebookStack, type NotebookStackProps } from './NotebookStack';
20
+ import { type TypescriptEditorProps } from './TypescriptEditor';
21
+
22
+ // TODO(burdon): Support calling named deployed functions (as with sheet).
23
+
24
+ export type NotebookContainerProps = {
25
+ role?: string;
26
+ notebook?: Notebook.Notebook;
27
+ } & Pick<TypescriptEditorProps, 'env'>;
28
+
29
+ export const NotebookContainer = ({ notebook, env }: NotebookContainerProps) => {
30
+ const { t } = useTranslation(meta.id);
31
+ const space = getSpace(notebook);
32
+ const graph = useMemo(() => notebook && new ComputeGraph(notebook), [notebook]);
33
+
34
+ // TODO(burdon): Cache values in context (preserve when switched).
35
+ const handleCompute = useCallback(() => {
36
+ graph?.evaluate();
37
+ }, [graph]);
38
+
39
+ const handleRearrange = useCallback<NonNullable<NotebookStackProps['onRearrange']>>(
40
+ (source, target) => {
41
+ invariant(notebook);
42
+ const from = notebook.cells.findIndex((cell) => cell.id === source.id);
43
+ const to = notebook.cells.findIndex((cell) => cell.id === target.id);
44
+ if (from != null && to != null) {
45
+ const cell = notebook.cells.splice(from, 1)[0];
46
+ if (cell) {
47
+ notebook.cells.splice(to, 0, cell);
48
+ }
49
+ }
50
+ },
51
+ [notebook],
52
+ );
53
+
54
+ const handleCellInsert = useCallback<NonNullable<NotebookStackProps['onCellInsert']>>(
55
+ (type, after) => {
56
+ invariant(notebook);
57
+ const cell: Notebook.Cell = { id: crypto.randomUUID(), type };
58
+ switch (type) {
59
+ case 'markdown':
60
+ case 'script':
61
+ case 'query': {
62
+ cell.script = Ref.make(DataType.makeText());
63
+ break;
64
+ }
65
+
66
+ case 'prompt': {
67
+ if (space) {
68
+ cell.chat = Ref.make(Assistant.makeChat({ queue: space.queues.create() }));
69
+ }
70
+ break;
71
+ }
72
+ }
73
+
74
+ const idx = after ? notebook.cells.findIndex((cell) => cell.id === after) : notebook.cells.length;
75
+ notebook.cells.splice(idx, 0, cell);
76
+ },
77
+ [space, notebook],
78
+ );
79
+
80
+ const handleCellDelete = useCallback<NonNullable<NotebookStackProps['onCellDelete']>>(
81
+ (id) => {
82
+ invariant(notebook);
83
+ const idx = notebook.cells.findIndex((cell) => cell.id === id);
84
+ if (idx !== -1) {
85
+ notebook.cells.splice(idx, 1);
86
+ }
87
+ },
88
+ [notebook],
89
+ );
90
+
91
+ return (
92
+ <StackItem.Content toolbar>
93
+ <Toolbar.Root textBlockWidth>
94
+ <DropdownMenu.Root>
95
+ <DropdownMenu.Trigger asChild>
96
+ <IconButton icon='ph--plus--regular' iconOnly label={t('notebook cell insert label')} />
97
+ </DropdownMenu.Trigger>
98
+ <NotebookMenu onCellInsert={handleCellInsert} />
99
+ </DropdownMenu.Root>
100
+ <Toolbar.IconButton
101
+ icon='ph--play--fill'
102
+ iconOnly
103
+ label={t('compute label')}
104
+ classNames='text-green-500'
105
+ onClick={handleCompute}
106
+ />
107
+ </Toolbar.Root>
108
+ <div role='none' className='flex bs-full overflow-hidden -mis-[1px] -mie-[1px]'>
109
+ <NotebookStack
110
+ classNames='container-max-width border-l border-r border-subduedSeparator'
111
+ space={space}
112
+ notebook={notebook}
113
+ graph={graph}
114
+ env={env}
115
+ onRearrange={handleRearrange}
116
+ onCellInsert={handleCellInsert}
117
+ onCellDelete={handleCellDelete}
118
+ />
119
+ </div>
120
+ </StackItem.Content>
121
+ );
122
+ };
123
+
124
+ export default NotebookContainer;
@@ -0,0 +1,217 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo } from 'react';
6
+
7
+ import { Surface } from '@dxos/app-framework';
8
+ import { Query, Ref } from '@dxos/echo';
9
+ import { QueryBuilder } from '@dxos/echo-query';
10
+ import { invariant } from '@dxos/invariant';
11
+ import { useChatProcessor, useChatServices } from '@dxos/plugin-assistant';
12
+ import { Chat } from '@dxos/plugin-assistant';
13
+ import { Graph } from '@dxos/plugin-explorer/types';
14
+ import { createDocAccessor } from '@dxos/react-client/echo';
15
+ import { type Space } from '@dxos/react-client/echo';
16
+ import { useAsyncEffect, useThemeContext, useTranslation } from '@dxos/react-ui';
17
+ import { QueryEditor, type QueryEditorProps } from '@dxos/react-ui-components';
18
+ import {
19
+ Editor,
20
+ type EditorProps,
21
+ createBasicExtensions,
22
+ createDataExtensions,
23
+ createMarkdownExtensions,
24
+ createThemeExtensions,
25
+ decorateMarkdown,
26
+ } from '@dxos/react-ui-editor';
27
+ import { mx } from '@dxos/react-ui-theme';
28
+ import { isNonNullable } from '@dxos/util';
29
+
30
+ import { meta } from '../../meta';
31
+ import { type ComputeGraph } from '../../notebook';
32
+ import { type Notebook } from '../../types';
33
+ import { TypescriptEditor, type TypescriptEditorProps } from '../TypescriptEditor';
34
+
35
+ import { type NotebookMenuProps } from './NotebookMenu';
36
+
37
+ const editorStyles = 'p-2 pis-3';
38
+ const valueStyles = 'p-1 pis-3';
39
+
40
+ export type NotebookCellProps = {
41
+ space?: Space;
42
+ graph?: ComputeGraph;
43
+ dragging?: boolean;
44
+ cell: Notebook.Cell;
45
+ } & (Pick<NotebookMenuProps, 'onCellInsert' | 'onCellDelete'> & Pick<TypescriptEditorProps, 'env'>);
46
+
47
+ // TODO(burdon): Display errors.
48
+ export const NotebookCell = ({ space, graph, dragging, cell, env }: NotebookCellProps) => {
49
+ const { t } = useTranslation(meta.id);
50
+
51
+ //
52
+ // Common.
53
+ //
54
+ const extensions = useMemo(() => {
55
+ return cell.script?.target
56
+ ? [createDataExtensions({ id: cell.id, text: createDocAccessor(cell.script.target, ['content']) })].filter(
57
+ isNonNullable,
58
+ )
59
+ : [];
60
+ }, [cell.script?.target]);
61
+
62
+ //
63
+ // Query.
64
+ //
65
+ const view = cell.view?.target;
66
+ const builder = useMemo(() => new QueryBuilder(), []);
67
+ useAsyncEffect(async () => {
68
+ if (!space || !cell.script?.target) {
69
+ return;
70
+ }
71
+
72
+ if (cell.type === 'query') {
73
+ const query = cell.script.target.content;
74
+ const filter = builder.build(query);
75
+ if (filter) {
76
+ const ast = Query.select(filter).ast;
77
+ const view = cell.view?.target;
78
+ if (!view) {
79
+ const graph = Graph.make({ query: { ast } });
80
+ const { view } = await Graph.makeView({ space, presentation: graph });
81
+ cell.view = Ref.make(view);
82
+ } else {
83
+ view.query.ast = ast;
84
+ }
85
+ }
86
+ }
87
+ }, [space, builder, cell, cell.script?.target?.content]);
88
+
89
+ const handleQueryChange = useCallback<NonNullable<QueryEditorProps['onChange']>>(
90
+ (value: string) => {
91
+ invariant(cell.script?.target);
92
+ cell.script.target.content = value;
93
+ },
94
+ [cell],
95
+ );
96
+
97
+ //
98
+ // Prompt.
99
+ // TODO(burdon): Add values to context or system message (via blueprint?).
100
+ //
101
+ const services = useChatServices({ space, chat: cell.chat?.target });
102
+ const processor = useChatProcessor({ chat: cell.chat?.target, services });
103
+
104
+ switch (cell.type) {
105
+ case 'markdown':
106
+ if (!cell.script?.target) {
107
+ return null;
108
+ }
109
+
110
+ return (
111
+ <MarkdownEditor
112
+ id={cell.id}
113
+ classNames={editorStyles}
114
+ initialValue={cell.script.target.content}
115
+ extensions={extensions}
116
+ />
117
+ );
118
+
119
+ case 'script':
120
+ if (!cell.script?.target) {
121
+ return null;
122
+ }
123
+
124
+ return (
125
+ <>
126
+ <TypescriptEditor
127
+ id={cell.id}
128
+ role='section'
129
+ classNames={editorStyles}
130
+ initialValue={cell.script.target.content}
131
+ extensions={extensions}
132
+ env={env}
133
+ options={{
134
+ placeholder: t('notebook cell placeholder'),
135
+ highlightActiveLine: false,
136
+ lineNumbers: false,
137
+ }}
138
+ />
139
+ <NotebookCellValue cell={cell} graph={graph} />
140
+ </>
141
+ );
142
+
143
+ case 'query':
144
+ if (!cell.script?.target) {
145
+ return null;
146
+ }
147
+
148
+ return (
149
+ <div className={mx('bs-full overflow-hidden grid', view && !dragging && 'grid-rows-[min-content_1fr]')}>
150
+ <QueryEditor
151
+ id={cell.id}
152
+ classNames={[editorStyles, 'border-b border-subduedSeparator']}
153
+ db={space?.db}
154
+ value={cell.script.target.content}
155
+ onChange={handleQueryChange}
156
+ />
157
+ {view && !dragging && <Surface role='section' limit={1} data={{ subject: view }} />}
158
+ </div>
159
+ );
160
+
161
+ case 'prompt':
162
+ if (!cell.chat?.target || !processor) {
163
+ return null;
164
+ }
165
+
166
+ return (
167
+ <Chat.Root chat={cell.chat.target} processor={processor}>
168
+ <Chat.Thread overscroll={0} />
169
+ <Chat.Prompt settings={false} classNames='p-2 border-t border-subduedSeparator' />
170
+ </Chat.Root>
171
+ );
172
+
173
+ default:
174
+ return null;
175
+ }
176
+ };
177
+
178
+ const NotebookCellValue = ({ cell, graph }: NotebookCellProps) => {
179
+ const name = graph?.expressions.value[cell.id]?.name;
180
+ const value = graph?.values.value[cell.id];
181
+ if (value == null) {
182
+ return null;
183
+ }
184
+
185
+ return (
186
+ <div
187
+ className={mx(
188
+ 'flex is-full bg-groupSurface border-t border-subduedSeparator text-description font-mono',
189
+ valueStyles,
190
+ )}
191
+ >
192
+ {name && (
193
+ <>
194
+ <span className='text-successText'>{name}</span>
195
+ <span className='text-description'>&nbsp;=&nbsp;</span>
196
+ </>
197
+ )}
198
+ <span>{value}</span>
199
+ </div>
200
+ );
201
+ };
202
+
203
+ const MarkdownEditor = ({ extensions: extensionsParam, ...props }: EditorProps) => {
204
+ const { t } = useTranslation(meta.id);
205
+ const { themeMode } = useThemeContext();
206
+ const extensions = useMemo(() => {
207
+ return [
208
+ createBasicExtensions({ placeholder: t('notebook markdown placeholder') }),
209
+ createThemeExtensions({ themeMode, syntaxHighlighting: true }),
210
+ createMarkdownExtensions(),
211
+ decorateMarkdown(),
212
+ extensionsParam,
213
+ ].filter(isNonNullable);
214
+ }, [extensionsParam]);
215
+
216
+ return <Editor {...props} extensions={extensions} moveToEnd />;
217
+ };
@@ -0,0 +1,47 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { DropdownMenu, useTranslation } from '@dxos/react-ui';
8
+
9
+ import { meta } from '../../meta';
10
+ import { type Notebook } from '../../types';
11
+
12
+ export type NotebookMenuProps = {
13
+ cell?: Notebook.Cell;
14
+ onCellInsert?: (type: Notebook.CellType, after: string | undefined) => void;
15
+ onCellDelete?: (id: string) => void;
16
+ };
17
+
18
+ // TODO(burdon): Better way to organize menu?
19
+ export const NotebookMenu = ({ cell, onCellInsert, onCellDelete }: NotebookMenuProps) => {
20
+ const { t } = useTranslation(meta.id);
21
+ return (
22
+ <DropdownMenu.Portal>
23
+ <DropdownMenu.Content>
24
+ <DropdownMenu.Viewport>
25
+ <DropdownMenu.Item onClick={() => onCellInsert?.('script', cell?.id)}>
26
+ {t('notebook cell insert script label')}
27
+ </DropdownMenu.Item>
28
+ <DropdownMenu.Item onClick={() => onCellInsert?.('prompt', cell?.id)}>
29
+ {t('notebook cell insert prompt label')}
30
+ </DropdownMenu.Item>
31
+ <DropdownMenu.Item onClick={() => onCellInsert?.('query', cell?.id)}>
32
+ {t('notebook cell insert query label')}
33
+ </DropdownMenu.Item>
34
+ <DropdownMenu.Item onClick={() => onCellInsert?.('markdown', cell?.id)}>
35
+ {t('notebook cell insert markdown label')}
36
+ </DropdownMenu.Item>
37
+ {cell && onCellDelete && (
38
+ <DropdownMenu.Item onClick={() => onCellDelete?.(cell.id)}>
39
+ {t('notebook cell delete label')}
40
+ </DropdownMenu.Item>
41
+ )}
42
+ </DropdownMenu.Viewport>
43
+ <DropdownMenu.Arrow />
44
+ </DropdownMenu.Content>
45
+ </DropdownMenu.Portal>
46
+ );
47
+ };
@@ -0,0 +1,32 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+
7
+ import { withClientProvider } from '@dxos/react-client/testing';
8
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
9
+
10
+ import { createNotebook } from '../../testing';
11
+ import { translations } from '../../translations';
12
+
13
+ import { NotebookStack } from './NotebookStack';
14
+
15
+ const meta = {
16
+ title: 'plugins/plugin-script/NotebookStack',
17
+ component: NotebookStack,
18
+ decorators: [withTheme, withLayout({ container: 'column', classNames: 'is-prose' }), withClientProvider()],
19
+ parameters: {
20
+ translations,
21
+ },
22
+ } satisfies Meta<typeof NotebookStack>;
23
+
24
+ export default meta;
25
+
26
+ type Story = StoryObj<typeof meta>;
27
+
28
+ export const Default: Story = {
29
+ args: {
30
+ notebook: createNotebook(),
31
+ },
32
+ };
@@ -0,0 +1,79 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { DropdownMenu, IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';
8
+ import { Stack, StackItem, type StackProps } from '@dxos/react-ui-stack';
9
+
10
+ import { meta } from '../../meta';
11
+ import { type Notebook } from '../../types';
12
+ import { type TypescriptEditorProps } from '../TypescriptEditor';
13
+
14
+ import { NotebookCell, type NotebookCellProps } from './NotebookCell';
15
+ import { NotebookMenu } from './NotebookMenu';
16
+
17
+ const minSectionHeight = 'min-bs-[16rem]';
18
+
19
+ export type NotebookStackProps = ThemedClassName<
20
+ {
21
+ notebook?: Notebook.Notebook;
22
+ onRearrange?: StackProps['onRearrange'];
23
+ } & (Pick<NotebookSectionProps, 'space' | 'graph' | 'onCellInsert' | 'onCellDelete'> &
24
+ Pick<TypescriptEditorProps, 'env'>)
25
+ >;
26
+
27
+ // TODO(burdon): Option for narrow rail (with compact buttons that align with first button in toolbar).
28
+ export const NotebookStack = ({ classNames, notebook, onRearrange, ...props }: NotebookStackProps) => {
29
+ return (
30
+ <Stack classNames={classNames} orientation='vertical' size='contain' rail onRearrange={onRearrange}>
31
+ {notebook?.cells.map((cell, i) => (
32
+ <NotebookSection key={i} cell={cell} {...props} />
33
+ ))}
34
+ </Stack>
35
+ );
36
+ };
37
+
38
+ type NotebookSectionProps = NotebookCellProps;
39
+
40
+ const NotebookSection = ({ cell, space, env, onCellInsert, onCellDelete, ...props }: NotebookSectionProps) => {
41
+ const { t } = useTranslation(meta.id);
42
+ const resizable = cell.type === 'query' || cell.type === 'prompt';
43
+
44
+ // TOOD(burdon): Set size if no extrinsic size (provider).
45
+ return (
46
+ <StackItem.Root role='section' item={cell} draggable classNames={resizable && minSectionHeight}>
47
+ <StackItem.Heading classNames='bs-full p-1 justify-between attention-surface'>
48
+ <StackItem.DragHandle asChild>
49
+ <IconButton variant='ghost' icon='ph--dots-six-vertical--regular' iconOnly label='Drag handle' />
50
+ </StackItem.DragHandle>
51
+ <DropdownMenu.Root>
52
+ <DropdownMenu.Trigger asChild>
53
+ <IconButton
54
+ variant='ghost'
55
+ icon='ph--dots-three--regular'
56
+ iconOnly
57
+ label={t('notebook cell insert label')}
58
+ />
59
+ </DropdownMenu.Trigger>
60
+ <NotebookMenu cell={cell} onCellInsert={onCellInsert} onCellDelete={onCellDelete} />
61
+ </DropdownMenu.Root>
62
+ {resizable && <StackItem.ResizeHandle />}
63
+ </StackItem.Heading>
64
+
65
+ {/* TODO(burdon): Move drag preview to outer stack (uniformly). */}
66
+ <StackItem.DragPreview>
67
+ {({ item: cell }) => (
68
+ <StackItem.Content classNames='overflow-visible bg-groupSurface border border-subduedSeparator'>
69
+ <NotebookCell space={space} cell={cell} env={env} dragging />
70
+ </StackItem.Content>
71
+ )}
72
+ </StackItem.DragPreview>
73
+
74
+ <StackItem.Content classNames='overflow-visible'>
75
+ <NotebookCell space={space} cell={cell} env={env} {...props} />
76
+ </StackItem.Content>
77
+ </StackItem.Root>
78
+ );
79
+ };
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './NotebookMenu';
6
+ export * from './NotebookStack';
@@ -11,7 +11,7 @@ import { createDataExtensions, listener, stackItemContentEditorClassNames } from
11
11
  import { StackItem } from '@dxos/react-ui-stack';
12
12
 
13
13
  import { useDeployState, useToolbarState } from '../hooks';
14
- import { type ScriptSettingsProps } from '../types';
14
+ import { type ScriptSettings } from '../types';
15
15
 
16
16
  import { ScriptToolbar } from './ScriptToolbar';
17
17
  import { TypescriptEditor, type TypescriptEditorProps } from './TypescriptEditor';
@@ -19,7 +19,7 @@ import { TypescriptEditor, type TypescriptEditorProps } from './TypescriptEditor
19
19
  export type ScriptEditorProps = {
20
20
  role: string;
21
21
  script: ScriptType;
22
- settings?: ScriptSettingsProps;
22
+ settings?: ScriptSettings;
23
23
  } & Pick<TypescriptEditorProps, 'env'>;
24
24
 
25
25
  export const ScriptContainer = ({ role, script, settings = { editorInputMode: 'vscode' }, env }: ScriptEditorProps) => {
@@ -2,21 +2,33 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
6
 
7
+ import { IntentPlugin } from '@dxos/app-framework';
8
+ import { withPluginManager } from '@dxos/app-framework/testing';
9
9
  import { Obj, Ref } from '@dxos/echo';
10
10
  import { ScriptType } from '@dxos/functions';
11
+ import { ClientPlugin } from '@dxos/plugin-client';
12
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
13
  import { DataType } from '@dxos/schema';
12
- import { withLayout, withTheme } from '@dxos/storybook-utils';
14
+
15
+ import { translations } from '../../translations';
13
16
 
14
17
  import { ScriptToolbar } from './ScriptToolbar';
15
18
 
16
19
  const meta = {
17
20
  title: 'plugins/plugin-script/Toolbar',
18
21
  component: ScriptToolbar,
19
- decorators: [withTheme, withLayout()],
22
+ // TODO(wittjosiah): Try to write story which does not depend on plugin manager.
23
+ decorators: [
24
+ withTheme,
25
+ withLayout({ classNames: 'is-prose' }),
26
+ withPluginManager({ plugins: [IntentPlugin(), ClientPlugin({})] }),
27
+ ],
28
+ parameters: {
29
+ layout: 'centered',
30
+ translations,
31
+ },
20
32
  } satisfies Meta<typeof ScriptToolbar>;
21
33
 
22
34
  export default meta;
@@ -25,11 +37,11 @@ type Story = StoryObj<typeof meta>;
25
37
 
26
38
  export const Default: Story = {
27
39
  args: {
40
+ state: {},
28
41
  script: Obj.make(ScriptType, {
29
42
  name: 'test',
30
43
  description: 'test',
31
44
  source: Ref.make(DataType.makeText('test')),
32
45
  }),
33
- state: {},
34
46
  },
35
47
  };
@@ -25,23 +25,7 @@ import {
25
25
  createTemplateSelect,
26
26
  useDeployDeps,
27
27
  } from '../../hooks';
28
- import { SCRIPT_PLUGIN } from '../../meta';
29
-
30
- const createToolbarActions = ({ state, script, ...options }: CreateDeployOptions): Rx.Rx<ActionGraphProps> =>
31
- Rx.make((get) =>
32
- get(
33
- rxFromSignal(() => {
34
- const templateSelect = createTemplateSelect(script);
35
- const format = createFormat(script);
36
- const gap = createGapSeparator();
37
- const deploy = createDeploy({ state, script, ...options });
38
- return {
39
- nodes: [...templateSelect.nodes, ...format.nodes, ...gap.nodes, ...deploy.nodes],
40
- edges: [...templateSelect.edges, ...format.edges, ...gap.edges, ...deploy.edges],
41
- };
42
- }),
43
- ),
44
- );
28
+ import { meta } from '../../meta';
45
29
 
46
30
  export type ScriptToolbarProps = ThemedClassName<{
47
31
  role?: string;
@@ -50,19 +34,32 @@ export type ScriptToolbarProps = ThemedClassName<{
50
34
  }>;
51
35
 
52
36
  export const ScriptToolbar = ({ script, role, state, classNames }: ScriptToolbarProps) => {
53
- const { t } = useTranslation(SCRIPT_PLUGIN);
37
+ const { t } = useTranslation(meta.id);
54
38
  const options = useDeployDeps({ script });
55
- const toolbarCreator = useMemo(
56
- () => createToolbarActions({ state, script, t, ...options }),
57
- [state, script, options, t],
58
- );
59
- const menu = useMenuActions(toolbarCreator);
39
+ const menu = useMemo(() => createToolbarActions({ state, script, t, ...options }), [state, script, options, t]);
40
+ const actions = useMenuActions(menu);
60
41
 
61
42
  return (
62
43
  <ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
63
- <MenuProvider {...menu} attendableId={fullyQualifiedId(script)}>
44
+ <MenuProvider {...actions} attendableId={fullyQualifiedId(script)}>
64
45
  <ToolbarMenu classNames={classNames} />
65
46
  </MenuProvider>
66
47
  </ElevationProvider>
67
48
  );
68
49
  };
50
+
51
+ const createToolbarActions = ({ state, script, ...options }: CreateDeployOptions): Rx.Rx<ActionGraphProps> =>
52
+ Rx.make((get) =>
53
+ get(
54
+ rxFromSignal(() => {
55
+ const templateSelect = createTemplateSelect(script);
56
+ const format = createFormat(script);
57
+ const gap = createGapSeparator();
58
+ const deploy = createDeploy({ state, script, ...options });
59
+ return {
60
+ nodes: [...templateSelect.nodes, ...format.nodes, ...gap.nodes, ...deploy.nodes],
61
+ edges: [...templateSelect.edges, ...format.edges, ...gap.edges, ...deploy.edges],
62
+ };
63
+ }),
64
+ ),
65
+ );