@dxos/plugin-script 0.6.11-staging.e6894a4 → 0.6.12-main.15a606f

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 (181) hide show
  1. package/dist/lib/browser/{ScriptEditor-YLGNCLXA.mjs → ScriptContainer-7DE7USCY.mjs} +260 -110
  2. package/dist/lib/browser/ScriptContainer-7DE7USCY.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-O4LWBX6A.mjs → chunk-CAEANETO.mjs} +2 -2
  4. package/dist/lib/browser/{chunk-O4LWBX6A.mjs.map → chunk-CAEANETO.mjs.map} +2 -2
  5. package/dist/lib/browser/{chunk-DL5XQRQM.mjs → chunk-G6FWCTGT.mjs} +7 -5
  6. package/dist/lib/browser/chunk-G6FWCTGT.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-RHEZ5LUU.mjs → chunk-G6H56WFS.mjs} +51 -2
  8. package/dist/lib/browser/{chunk-RHEZ5LUU.mjs.map → chunk-G6H56WFS.mjs.map} +4 -4
  9. package/dist/lib/browser/{chunk-JBACGDOJ.mjs → chunk-MDX7ACIK.mjs} +3 -6
  10. package/dist/lib/browser/chunk-MDX7ACIK.mjs.map +7 -0
  11. package/dist/lib/browser/edge/index.mjs +3 -1
  12. package/dist/lib/browser/index.mjs +80 -61
  13. package/dist/lib/browser/index.mjs.map +4 -4
  14. package/dist/lib/browser/meta.json +1 -1
  15. package/dist/lib/browser/meta.mjs +1 -1
  16. package/dist/lib/browser/types/index.mjs +2 -2
  17. package/dist/lib/node/ScriptContainer-J76LKPAM.cjs +667 -0
  18. package/dist/lib/node/ScriptContainer-J76LKPAM.cjs.map +7 -0
  19. package/dist/lib/node/{chunk-5RBVXKXT.cjs → chunk-2PZKJXNP.cjs} +6 -6
  20. package/dist/lib/node/{chunk-5RBVXKXT.cjs.map → chunk-2PZKJXNP.cjs.map} +2 -2
  21. package/dist/lib/node/{chunk-4GTXIELQ.cjs → chunk-ACLCRWDB.cjs} +44 -6
  22. package/dist/lib/node/chunk-ACLCRWDB.cjs.map +7 -0
  23. package/dist/lib/node/{TypescriptEditor-CRONCQSI.cjs → chunk-OJ77BZRH.cjs} +19 -8
  24. package/dist/lib/node/chunk-OJ77BZRH.cjs.map +7 -0
  25. package/dist/lib/node/{chunk-PFH3ROEH.cjs → chunk-UZ3ZXEBF.cjs} +11 -8
  26. package/dist/lib/node/chunk-UZ3ZXEBF.cjs.map +7 -0
  27. package/dist/lib/node/edge/index.cjs +10 -8
  28. package/dist/lib/node/edge/index.cjs.map +2 -2
  29. package/dist/lib/node/index.cjs +93 -79
  30. package/dist/lib/node/index.cjs.map +4 -4
  31. package/dist/lib/node/meta.cjs +3 -3
  32. package/dist/lib/node/meta.cjs.map +1 -1
  33. package/dist/lib/node/meta.json +1 -1
  34. package/dist/lib/node/types/index.cjs +5 -5
  35. package/dist/lib/node/types/index.cjs.map +1 -1
  36. package/dist/lib/node-esm/ScriptContainer-F6ACEA63.mjs +665 -0
  37. package/dist/lib/node-esm/ScriptContainer-F6ACEA63.mjs.map +7 -0
  38. package/dist/lib/node-esm/chunk-2NX3HWPM.mjs +245 -0
  39. package/dist/lib/node-esm/chunk-2NX3HWPM.mjs.map +7 -0
  40. package/dist/lib/node-esm/chunk-7BZDZF7Z.mjs +47 -0
  41. package/dist/lib/node-esm/chunk-7BZDZF7Z.mjs.map +7 -0
  42. package/dist/lib/node-esm/chunk-LDLNTVAK.mjs +280 -0
  43. package/dist/lib/node-esm/chunk-LDLNTVAK.mjs.map +7 -0
  44. package/dist/lib/node-esm/chunk-TZ3Z4SII.mjs +20 -0
  45. package/dist/lib/node-esm/chunk-TZ3Z4SII.mjs.map +7 -0
  46. package/dist/lib/node-esm/edge/index.mjs +22 -0
  47. package/dist/lib/node-esm/index.mjs +311 -0
  48. package/dist/lib/node-esm/index.mjs.map +7 -0
  49. package/dist/lib/node-esm/meta.json +1 -0
  50. package/dist/lib/node-esm/meta.mjs +10 -0
  51. package/dist/lib/node-esm/meta.mjs.map +7 -0
  52. package/dist/lib/node-esm/types/index.mjs +13 -0
  53. package/dist/lib/node-esm/types/index.mjs.map +7 -0
  54. package/dist/types/src/ScriptPlugin.d.ts.map +1 -1
  55. package/dist/types/src/components/DebugPanel/DebugPanel.d.ts.map +1 -0
  56. package/dist/types/src/components/DebugPanel/index.d.ts +2 -0
  57. package/dist/types/src/components/DebugPanel/index.d.ts.map +1 -0
  58. package/dist/types/src/components/{ScriptBlock/FrameContainer → FrameContainer}/FrameContainer.d.ts +1 -1
  59. package/dist/types/src/components/FrameContainer/FrameContainer.d.ts.map +1 -0
  60. package/dist/types/src/components/FrameContainer/frame.d.ts.map +1 -0
  61. package/dist/types/src/components/FrameContainer/index.d.ts.map +1 -0
  62. package/dist/types/src/components/ScriptBlock/ScriptBlock.d.ts +1 -3
  63. package/dist/types/src/components/ScriptBlock/ScriptBlock.d.ts.map +1 -1
  64. package/dist/types/src/components/ScriptBlock/ScriptBlock.stories.d.ts +2 -5
  65. package/dist/types/src/components/ScriptBlock/ScriptBlock.stories.d.ts.map +1 -1
  66. package/dist/types/src/components/ScriptContainer.d.ts +5 -0
  67. package/dist/types/src/components/ScriptContainer.d.ts.map +1 -0
  68. package/dist/types/src/components/ScriptEditor.d.ts +4 -5
  69. package/dist/types/src/components/ScriptEditor.d.ts.map +1 -1
  70. package/dist/types/src/components/ScriptSettings/ScriptSettings.d.ts +6 -0
  71. package/dist/types/src/components/ScriptSettings/ScriptSettings.d.ts.map +1 -0
  72. package/dist/types/src/components/ScriptSettings/index.d.ts +2 -0
  73. package/dist/types/src/components/ScriptSettings/index.d.ts.map +1 -0
  74. package/dist/types/src/components/Toolbar/Toolbar.d.ts +23 -0
  75. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
  76. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +17 -0
  77. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
  78. package/dist/types/src/components/Toolbar/index.d.ts +2 -0
  79. package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
  80. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.d.ts +10 -0
  81. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.d.ts.map +1 -0
  82. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.stories.d.ts +10 -0
  83. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.stories.d.ts.map +1 -0
  84. package/dist/types/src/components/TypescriptEditor/index.d.ts +2 -0
  85. package/dist/types/src/components/TypescriptEditor/index.d.ts.map +1 -0
  86. package/dist/types/src/components/index.d.ts +2 -2
  87. package/dist/types/src/components/index.d.ts.map +1 -1
  88. package/dist/types/src/edge/functions.d.ts +1 -0
  89. package/dist/types/src/edge/functions.d.ts.map +1 -1
  90. package/dist/types/src/meta.d.ts +1 -4
  91. package/dist/types/src/meta.d.ts.map +1 -1
  92. package/dist/types/src/templates/chat.d.ts +6 -0
  93. package/dist/types/src/templates/chat.d.ts.map +1 -0
  94. package/dist/types/src/templates/chess.d.ts +6 -0
  95. package/dist/types/src/templates/chess.d.ts.map +1 -0
  96. package/dist/types/src/templates/echo.d.ts +6 -0
  97. package/dist/types/src/templates/echo.d.ts.map +1 -0
  98. package/dist/types/src/templates/email.d.ts +6 -0
  99. package/dist/types/src/templates/email.d.ts.map +1 -0
  100. package/dist/types/src/templates/forex.d.ts +6 -0
  101. package/dist/types/src/templates/forex.d.ts.map +1 -0
  102. package/dist/types/src/templates.d.ts +8 -0
  103. package/dist/types/src/templates.d.ts.map +1 -0
  104. package/dist/types/src/translations.d.ts +2 -0
  105. package/dist/types/src/translations.d.ts.map +1 -1
  106. package/dist/types/src/types/script.d.ts +4 -4
  107. package/dist/types/src/types/types.d.ts +4 -3
  108. package/dist/types/src/types/types.d.ts.map +1 -1
  109. package/package.json +54 -47
  110. package/src/ScriptPlugin.tsx +21 -36
  111. package/src/bundler/bundler.test.ts +12 -2
  112. package/src/components/{DebugPanel.tsx → DebugPanel/DebugPanel.tsx} +49 -56
  113. package/src/components/DebugPanel/index.ts +5 -0
  114. package/src/components/{ScriptBlock/FrameContainer → FrameContainer}/FrameContainer.tsx +1 -1
  115. package/src/components/ScriptBlock/ScriptBlock.stories.tsx +29 -21
  116. package/src/components/ScriptBlock/ScriptBlock.tsx +10 -36
  117. package/src/components/ScriptContainer.tsx +22 -0
  118. package/src/components/ScriptEditor.tsx +46 -30
  119. package/src/components/ScriptSettings/ScriptSettings.tsx +47 -0
  120. package/src/components/ScriptSettings/index.ts +5 -0
  121. package/src/components/Toolbar/Toolbar.stories.tsx +26 -0
  122. package/src/components/Toolbar/Toolbar.tsx +180 -0
  123. package/src/components/{ScriptBlock/Splitter → Toolbar}/index.ts +1 -1
  124. package/src/components/{TypescriptEditor.stories.tsx → TypescriptEditor/TypescriptEditor.stories.tsx} +12 -36
  125. package/src/components/{TypescriptEditor.tsx → TypescriptEditor/TypescriptEditor.tsx} +14 -18
  126. package/src/components/TypescriptEditor/index.ts +5 -0
  127. package/src/components/index.ts +3 -2
  128. package/src/edge/functions.ts +1 -0
  129. package/src/meta.tsx +2 -6
  130. package/src/templates/chat.ts +102 -0
  131. package/src/templates/chess.ts +41 -0
  132. package/src/templates/echo.ts +15 -0
  133. package/src/templates/email.ts +38 -0
  134. package/src/templates/forex.ts +21 -0
  135. package/src/templates.ts +54 -0
  136. package/src/translations.ts +2 -0
  137. package/src/types/types.ts +9 -5
  138. package/dist/lib/browser/ScriptEditor-YLGNCLXA.mjs.map +0 -7
  139. package/dist/lib/browser/TypescriptEditor-XTGRVCMY.mjs +0 -9
  140. package/dist/lib/browser/chunk-DL5XQRQM.mjs.map +0 -7
  141. package/dist/lib/browser/chunk-DX5CSOBP.mjs +0 -79
  142. package/dist/lib/browser/chunk-DX5CSOBP.mjs.map +0 -7
  143. package/dist/lib/browser/chunk-JBACGDOJ.mjs.map +0 -7
  144. package/dist/lib/node/ScriptEditor-XLE33DB4.cjs +0 -527
  145. package/dist/lib/node/ScriptEditor-XLE33DB4.cjs.map +0 -7
  146. package/dist/lib/node/TypescriptEditor-CRONCQSI.cjs.map +0 -7
  147. package/dist/lib/node/chunk-4GTXIELQ.cjs.map +0 -7
  148. package/dist/lib/node/chunk-4VMNBXWU.cjs +0 -54
  149. package/dist/lib/node/chunk-4VMNBXWU.cjs.map +0 -7
  150. package/dist/lib/node/chunk-PFH3ROEH.cjs.map +0 -7
  151. package/dist/lib/node/chunk-RXI576K3.cjs +0 -112
  152. package/dist/lib/node/chunk-RXI576K3.cjs.map +0 -7
  153. package/dist/types/src/components/DebugPanel.d.ts.map +0 -1
  154. package/dist/types/src/components/ScriptBlock/FrameContainer/FrameContainer.d.ts.map +0 -1
  155. package/dist/types/src/components/ScriptBlock/FrameContainer/frame.d.ts.map +0 -1
  156. package/dist/types/src/components/ScriptBlock/FrameContainer/index.d.ts.map +0 -1
  157. package/dist/types/src/components/ScriptBlock/Splitter/Splitter.d.ts +0 -15
  158. package/dist/types/src/components/ScriptBlock/Splitter/Splitter.d.ts.map +0 -1
  159. package/dist/types/src/components/ScriptBlock/Splitter/Splitter.stories.d.ts +0 -13
  160. package/dist/types/src/components/ScriptBlock/Splitter/Splitter.stories.d.ts.map +0 -1
  161. package/dist/types/src/components/ScriptBlock/Splitter/index.d.ts +0 -2
  162. package/dist/types/src/components/ScriptBlock/Splitter/index.d.ts.map +0 -1
  163. package/dist/types/src/components/Toolbar.d.ts +0 -13
  164. package/dist/types/src/components/Toolbar.d.ts.map +0 -1
  165. package/dist/types/src/components/Toolbar.stories.d.ts +0 -16
  166. package/dist/types/src/components/Toolbar.stories.d.ts.map +0 -1
  167. package/dist/types/src/components/TypescriptEditor.d.ts +0 -12
  168. package/dist/types/src/components/TypescriptEditor.d.ts.map +0 -1
  169. package/dist/types/src/components/TypescriptEditor.stories.d.ts +0 -13
  170. package/dist/types/src/components/TypescriptEditor.stories.d.ts.map +0 -1
  171. package/src/components/ScriptBlock/Splitter/Splitter.stories.tsx +0 -37
  172. package/src/components/ScriptBlock/Splitter/Splitter.tsx +0 -52
  173. package/src/components/Toolbar.stories.tsx +0 -19
  174. package/src/components/Toolbar.tsx +0 -146
  175. /package/dist/lib/{browser/TypescriptEditor-XTGRVCMY.mjs.map → node-esm/edge/index.mjs.map} +0 -0
  176. /package/dist/types/src/components/{DebugPanel.d.ts → DebugPanel/DebugPanel.d.ts} +0 -0
  177. /package/dist/types/src/components/{ScriptBlock/FrameContainer → FrameContainer}/frame.d.ts +0 -0
  178. /package/dist/types/src/components/{ScriptBlock/FrameContainer → FrameContainer}/index.d.ts +0 -0
  179. /package/src/components/{ScriptBlock/FrameContainer → FrameContainer}/frame.html +0 -0
  180. /package/src/components/{ScriptBlock/FrameContainer → FrameContainer}/frame.tsx +0 -0
  181. /package/src/components/{ScriptBlock/FrameContainer → FrameContainer}/index.ts +0 -0
@@ -3,15 +3,6 @@
3
3
  //
4
4
 
5
5
  import React, { useEffect, useRef, useState } from 'react';
6
- // @ts-ignore
7
- // eslint-disable-next-line no-restricted-imports
8
- import SyntaxHighlighter from 'react-syntax-highlighter';
9
- // @ts-ignore
10
- // eslint-disable-next-line no-restricted-imports
11
- import styleDark from 'react-syntax-highlighter/dist/esm/styles/hljs/a11y-dark';
12
- // @ts-ignore
13
- // eslint-disable-next-line no-restricted-imports
14
- import styleLight from 'react-syntax-highlighter/dist/esm/styles/hljs/a11y-light';
15
6
 
16
7
  import { log } from '@dxos/log';
17
8
  import {
@@ -22,12 +13,12 @@ import {
22
13
  type ThemedClassName,
23
14
  Toolbar,
24
15
  useControlledValue,
25
- useThemeContext,
26
16
  useTranslation,
27
17
  } from '@dxos/react-ui';
18
+ import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
28
19
  import { mx } from '@dxos/react-ui-theme';
29
20
 
30
- import { SCRIPT_PLUGIN } from '../meta';
21
+ import { SCRIPT_PLUGIN } from '../../meta';
31
22
 
32
23
  type State = 'pending' | 'responding';
33
24
 
@@ -56,7 +47,7 @@ export const DebugPanel = ({ classNames, functionUrl, binding: _binding, onBindi
56
47
  const [result, setResult] = useState('');
57
48
  const [state, setState] = useState<State | null>(null);
58
49
 
59
- // TODO(burdon): Persistent history (non-space ECHO data?)
50
+ // TODO(burdon): Persistent history -- at least for session (non-space ECHO data?)
60
51
  const [history, setHistory] = useState<Message[]>([]);
61
52
 
62
53
  const scrollerRef = useRef<HTMLDivElement>(null);
@@ -224,60 +215,62 @@ export const DebugPanel = ({ classNames, functionUrl, binding: _binding, onBindi
224
215
  );
225
216
  };
226
217
 
227
- const RobotAvatar = () => (
228
- <Avatar.Root size={6} variant='circle'>
229
- <Avatar.Frame>
230
- <Avatar.Icon icon='ph--robot--regular' />
231
- </Avatar.Frame>
232
- </Avatar.Root>
233
- );
234
-
235
- const MessageItem = ({ classNames, message }: ThemedClassName<{ message: Message }>) => {
236
- const { themeMode } = useThemeContext();
237
- const { text, data, error } = message;
238
- if (error) {
239
- return <span className={mx(classNames, 'whitespace-pre text-error')}>{String(error)}</span>;
240
- } else if (data) {
241
- return (
242
- <SyntaxHighlighter
243
- language='json'
244
- style={themeMode === 'dark' ? styleDark : styleLight}
245
- className={mx('w-full text-xs', classNames)}
246
- >
247
- {JSON.stringify(data, null, 2)}
248
- </SyntaxHighlighter>
249
- );
250
- }
251
-
252
- return <span className={mx(classNames)}>{text || '\u00D8'}</span>;
253
- };
254
-
255
218
  // TODO(burdon): Replace with thread?
256
219
  // TODO(burdon): Button to delete individual messages.
257
- // TODO(burdon): Button to re-run question.
220
+ // TODO(burdon): Button to edit/re-run question.
258
221
  const MessageThread = ({ state, result, history }: { state: State | null; result: string; history: Message[] }) => {
259
222
  return (
260
223
  <>
261
224
  {history.map((message, i) => (
262
- <div key={i} className='grid grid-cols-[3rem_1fr]'>
263
- <div>{message.type === 'response' && <RobotAvatar />}</div>
264
- <div className={mx('flex', message.type === 'request' && 'justify-end')}>
265
- <MessageItem
266
- classNames={[message.type === 'request' && 'p-1 px-2 rounded-lg bg-hoverSurface']}
267
- message={message}
268
- />
225
+ <div key={i} className='grid grid-cols-[3rem_1fr_3rem]'>
226
+ <div className='p-1'>{message.type === 'response' && <RobotAvatar />}</div>
227
+ <div className='overflow-auto'>
228
+ <MessageItem message={message} />
269
229
  </div>
270
230
  </div>
271
231
  ))}
272
- <div className='grid grid-cols-[3rem_1fr]'>
273
- <div>
274
- {(state === 'pending' && <Icon icon='ph--spinner--regular' size={6} classNames='animate-spin-slow' />) ||
275
- (result.length > 0 && <RobotAvatar />)}
276
- </div>
277
- <div>
278
- <span>{result}</span>
232
+ {result?.length > 0 && (
233
+ <div className='grid grid-cols-[3rem_1fr_3rem]'>
234
+ <div className='p-1'>
235
+ {(state === 'pending' && <Icon icon='ph--spinner--regular' size={6} classNames='animate-spin' />) || (
236
+ <Icon icon='ph--robot--regular' size={6} classNames='animate-[pulse_1s_ease-in-out_infinite]' />
237
+ )}
238
+ </div>
239
+ <div className='overflow-auto'>
240
+ <MessageItem message={{ type: 'response', text: result }} />
241
+ </div>
279
242
  </div>
280
- </div>
243
+ )}
281
244
  </>
282
245
  );
283
246
  };
247
+
248
+ const MessageItem = ({ classNames, message }: ThemedClassName<{ message: Message }>) => {
249
+ const { type, text, data, error } = message;
250
+ const wrapper = 'p-1 px-2 rounded-lg bg-hoverSurface overflow-auto';
251
+ return (
252
+ <div className={mx('flex', type === 'request' ? 'ml-[8rem] justify-end' : 'mr-[8rem]', classNames)}>
253
+ {error && <div className={mx(wrapper, 'whitespace-pre text-error')}>{String(error)}</div>}
254
+
255
+ {text !== undefined && (
256
+ <div className={mx(wrapper, type === 'request' && 'bg-primary-400 dark:bg-primary-600')}>
257
+ {text || '\u00D8'}
258
+ </div>
259
+ )}
260
+
261
+ {data && (
262
+ <SyntaxHighlighter language='json' className={mx(wrapper, 'px-8 py-2 text-xs')}>
263
+ {JSON.stringify(data, null, 2)}
264
+ </SyntaxHighlighter>
265
+ )}
266
+ </div>
267
+ );
268
+ };
269
+
270
+ const RobotAvatar = () => (
271
+ <Avatar.Root size={6} variant='circle'>
272
+ <Avatar.Frame>
273
+ <Avatar.Icon icon='ph--robot--regular' />
274
+ </Avatar.Frame>
275
+ </Avatar.Root>
276
+ );
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './DebugPanel';
@@ -11,7 +11,7 @@ import { baseSurface, mx } from '@dxos/react-ui-theme';
11
11
  import { createProtoRpcPeer } from '@dxos/rpc';
12
12
  import { createIFramePort } from '@dxos/rpc-tunnel';
13
13
 
14
- import { type BundlerResult } from '../../../bundler';
14
+ import { type BundlerResult } from '../../bundler';
15
15
 
16
16
  export type FrameContainerProps = {
17
17
  containerUrl: string;
@@ -9,14 +9,14 @@ import React, { useEffect, useMemo } from 'react';
9
9
  import { createSpaceObjectGenerator, TestSchemaType } from '@dxos/echo-generator';
10
10
  import { TextType } from '@dxos/plugin-markdown/types';
11
11
  import { useClient } from '@dxos/react-client';
12
- import { create, createDocAccessor, createEchoObject } from '@dxos/react-client/echo';
13
- import { ClientRepeater } from '@dxos/react-client/testing';
14
- import { withTheme } from '@dxos/storybook-utils';
12
+ import { create, createEchoObject, useSpaces } from '@dxos/react-client/echo';
13
+ import { withClientProvider } from '@dxos/react-client/testing';
14
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
15
15
 
16
- // @ts-ignore
17
- import mainUrl from './FrameContainer/frame?url';
18
16
  import { ScriptBlock } from './ScriptBlock';
19
17
  import { ScriptType } from '../../types';
18
+ // @ts-ignore
19
+ import mainUrl from '../FrameContainer/frame?url';
20
20
 
21
21
  const code = [
22
22
  "import { Filter, useQuery, useSpaces} from '@dxos/react-client/echo';",
@@ -32,33 +32,41 @@ const code = [
32
32
 
33
33
  const Story = () => {
34
34
  const client = useClient();
35
- // TODO(dmaretskyi): Review what's the right way to create automerge-backed objects.
35
+ const spaces = useSpaces();
36
+ console.log(spaces.length);
37
+
38
+ useEffect(() => {
39
+ try {
40
+ // TODO(burdon): Default not set.
41
+ const generator = createSpaceObjectGenerator(client.spaces.default);
42
+ generator.addSchemas();
43
+ void generator
44
+ .createObjects({
45
+ [TestSchemaType.organization]: 20,
46
+ [TestSchemaType.contact]: 50,
47
+ })
48
+ .catch();
49
+ } catch (err) {
50
+ console.log(err);
51
+ }
52
+ }, [client]);
53
+
54
+ // TODO(burdon): Review what's the right way to create automerge-backed objects.
36
55
  const object = useMemo(
37
56
  () => createEchoObject(create(ScriptType, { source: create(TextType, { content: code }) })),
38
- [code],
57
+ [],
39
58
  );
40
- const accessor = useMemo(() => createDocAccessor(object, ['content']), [object]);
41
- useEffect(() => {
42
- const generator = createSpaceObjectGenerator(client.spaces.default);
43
- generator.addSchemas();
44
- void generator.createObjects({ [TestSchemaType.organization]: 20, [TestSchemaType.contact]: 50 }).catch();
45
- }, []);
46
59
 
47
60
  // TODO(dmaretskyi): Not sure how to provide `containerUrl` here since the html now lives in composer-app.
48
61
  // TODO(burdon): Normalize html/frame.tsx with composer-app to test locally.
49
- return (
50
- <div className={'flex fixed inset-0'}>{accessor && <ScriptBlock script={object} containerUrl={mainUrl} />}</div>
51
- );
62
+ return <ScriptBlock script={object} containerUrl={mainUrl} />;
52
63
  };
53
64
 
54
65
  export default {
55
66
  title: 'plugin-script/ScriptBlock',
56
67
  component: ScriptBlock,
57
- render: () => <ClientRepeater component={Story} createSpace />,
58
- decorators: [withTheme],
59
- parameters: {
60
- layout: 'fullscreen',
61
- },
68
+ decorators: [withClientProvider({ createSpace: true }), withTheme, withLayout({ fullscreen: true, tooltips: true })],
69
+ render: Story,
62
70
  };
63
71
 
64
72
  export const Default = {};
@@ -2,19 +2,17 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Check, Play, Warning } from '@phosphor-icons/react';
6
5
  // @ts-ignore
7
6
  import wasmUrl from 'esbuild-wasm/esbuild.wasm?url';
8
7
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
9
8
 
10
9
  import { createDocAccessor, DocAccessor } from '@dxos/react-client/echo';
11
- import { DensityProvider, Toolbar, Button } from '@dxos/react-ui';
12
- import { mx, getSize } from '@dxos/react-ui-theme';
10
+ import { DensityProvider, Toolbar, Button, Icon } from '@dxos/react-ui';
11
+ import { mx } from '@dxos/react-ui-theme';
13
12
 
14
- import { FrameContainer } from './FrameContainer';
15
- import { Splitter, SplitterSelector, type View } from './Splitter';
16
13
  import { Bundler, type BundlerResult, initializeBundler } from '../../bundler';
17
14
  import { type ScriptType } from '../../types';
15
+ import { FrameContainer } from '../FrameContainer';
18
16
  import { ScriptEditor } from '../ScriptEditor';
19
17
 
20
18
  // Keep in sync with packages/apps/composer-app/script-frame/main.tsx .
@@ -29,7 +27,6 @@ const PROVIDED_MODULES = [
29
27
 
30
28
  export type ScriptBlockProps = {
31
29
  script: ScriptType;
32
- view?: View;
33
30
  hideSelector?: boolean;
34
31
  classes?: {
35
32
  root?: string;
@@ -44,17 +41,8 @@ export type ScriptBlockProps = {
44
41
  * @deprecated
45
42
  */
46
43
  // TODO(burdon): Cache compiled results in context.
47
- export const ScriptBlock = ({
48
- script,
49
- view: controlledView,
50
- hideSelector,
51
- classes,
52
- containerUrl,
53
- }: ScriptBlockProps) => {
44
+ export const ScriptBlock = ({ script, hideSelector, classes, containerUrl }: ScriptBlockProps) => {
54
45
  const source = useMemo(() => script.source && createDocAccessor(script.source, ['content']), [script.source]);
55
- const [view, setView] = useState<View>(controlledView ?? 'editor');
56
- useEffect(() => handleSetView(controlledView ?? 'editor'), [controlledView]);
57
-
58
46
  const [result, setResult] = useState<BundlerResult>();
59
47
  const bundler = useMemo(
60
48
  () => new Bundler({ platform: 'browser', sandboxedModules: PROVIDED_MODULES, remoteModules: {} }),
@@ -78,16 +66,6 @@ export const ScriptBlock = ({
78
66
  return () => clearTimeout(t);
79
67
  }, [source]);
80
68
 
81
- const handleSetView = useCallback(
82
- (view: View) => {
83
- setView(view);
84
- if (!result && view !== 'editor') {
85
- void handleExec(false);
86
- }
87
- },
88
- [result],
89
- );
90
-
91
69
  const handleExec = useCallback(
92
70
  async (auto = true) => {
93
71
  if (!source) {
@@ -95,11 +73,8 @@ export const ScriptBlock = ({
95
73
  }
96
74
  const result = await bundler.bundle(DocAccessor.getValue(source));
97
75
  setResult(result);
98
- if (auto && view === 'editor') {
99
- setView('preview');
100
- }
101
76
  },
102
- [source, view],
77
+ [source],
103
78
  );
104
79
 
105
80
  return (
@@ -107,29 +82,28 @@ export const ScriptBlock = ({
107
82
  {!hideSelector && (
108
83
  <DensityProvider density='fine'>
109
84
  <Toolbar.Root classNames={mx('mb-2', classes?.toolbar)}>
110
- <SplitterSelector view={view} onChange={handleSetView} />
111
85
  <div className='grow' />
112
86
  {result?.bundle && !result?.error && (
113
87
  <div title={String(result.error)}>
114
- <Check className={mx(getSize(5), 'text-green-500')} />
88
+ <Icon icon='ph--check--regular' size={5} classNames='text-green-500' />
115
89
  </div>
116
90
  )}
117
91
  {result?.error && (
118
92
  <div title={String(result.error)}>
119
- <Warning className={mx(getSize(5), 'text-orange-500')} />
93
+ <Icon icon='ph--warning--regular' size={5} classNames='text-orange-500' />
120
94
  </div>
121
95
  )}
122
96
  <Button variant='ghost' onClick={() => handleExec()}>
123
- <Play className={getSize(5)} />
97
+ <Icon icon='ph--play--regular' size={5} />
124
98
  </Button>
125
99
  </Toolbar.Root>
126
100
  </DensityProvider>
127
101
  )}
128
102
 
129
- <Splitter view={view}>
103
+ <div className='flex'>
130
104
  <ScriptEditor script={script} />
131
105
  {result && <FrameContainer key={script.id} result={result} containerUrl={containerUrl} />}
132
- </Splitter>
106
+ </div>
133
107
  </div>
134
108
  );
135
109
  };
@@ -0,0 +1,22 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { fullyQualifiedId } from '@dxos/react-client/echo';
8
+ import { useHasAttention } from '@dxos/react-ui-attention';
9
+ import { mx } from '@dxos/react-ui-theme';
10
+
11
+ import { ScriptEditor, type ScriptEditorProps } from './ScriptEditor';
12
+
13
+ const ScriptContainer = ({ script, ...props }: ScriptEditorProps) => {
14
+ const hasAttention = useHasAttention(fullyQualifiedId(script));
15
+ return (
16
+ <div role='none' className={mx('flex row-span-2 w-full overflow-hidden', hasAttention && 'attention-surface')}>
17
+ <ScriptEditor {...props} script={script} />
18
+ </div>
19
+ );
20
+ };
21
+
22
+ export default ScriptContainer;
@@ -12,12 +12,12 @@ import { log } from '@dxos/log';
12
12
  import { useClient } from '@dxos/react-client';
13
13
  import { create, createDocAccessor, Filter, getMeta, getSpace, useQuery } from '@dxos/react-client/echo';
14
14
  import { useIdentity } from '@dxos/react-client/halo';
15
- import { useTranslation } from '@dxos/react-ui';
15
+ import { useTranslation, type ThemedClassName } from '@dxos/react-ui';
16
16
  import { createDataExtensions, listener } from '@dxos/react-ui-editor';
17
17
  import { mx } from '@dxos/react-ui-theme';
18
18
 
19
19
  import { DebugPanel } from './DebugPanel';
20
- import { Toolbar } from './Toolbar';
20
+ import { type TemplateSelectProps, Toolbar, type ViewType } from './Toolbar';
21
21
  import { TypescriptEditor, type TypescriptEditorProps } from './TypescriptEditor';
22
22
  import { Bundler } from '../bundler';
23
23
  import {
@@ -25,16 +25,18 @@ import {
25
25
  publicKeyToDid,
26
26
  setUserFunctionUrlInMetadata,
27
27
  uploadWorkerFunction,
28
+ USERFUNCTIONS_PRESET_META_KEY,
28
29
  } from '../edge';
29
30
  import { SCRIPT_PLUGIN } from '../meta';
31
+ import { templates } from '../templates';
30
32
  import { FunctionType, type ScriptType } from '../types';
31
33
 
32
- export type ScriptEditorProps = {
34
+ export type ScriptEditorProps = ThemedClassName<{
33
35
  script: ScriptType;
34
- role?: string;
35
- } & Pick<TypescriptEditorProps, 'env'>;
36
+ }> &
37
+ Pick<TypescriptEditorProps, 'env'>;
36
38
 
37
- export const ScriptEditor = ({ env, script, role }: ScriptEditorProps) => {
39
+ export const ScriptEditor = ({ classNames, script, env }: ScriptEditorProps) => {
38
40
  const { t } = useTranslation(SCRIPT_PLUGIN);
39
41
  const client = useClient();
40
42
  const identity = useIdentity();
@@ -63,7 +65,7 @@ export const ScriptEditor = ({ env, script, role }: ScriptEditorProps) => {
63
65
  [script, script.source, space, identity],
64
66
  );
65
67
 
66
- const [showPanel, setShowPanel] = useState(false);
68
+ const [view, setView] = useState<ViewType>('editor');
67
69
  const initialValue = useMemo(() => script.source?.content, [script.source]);
68
70
  const existingFunctionUrl = fn && getUserFunctionUrlInMetadata(getMeta(fn));
69
71
  const [error, setError] = useState<string>();
@@ -93,6 +95,22 @@ export const ScriptEditor = ({ env, script, role }: ScriptEditorProps) => {
93
95
  }
94
96
  }, [script.source]);
95
97
 
98
+ const handleTemplateChange: TemplateSelectProps['onTemplateSelect'] = (id) => {
99
+ const template = templates.find((template) => template.id === id);
100
+ if (template) {
101
+ script.name = template.name;
102
+ script.source!.content = template.source;
103
+ const metaKeys = getMeta(script).keys;
104
+ const oldPresetIndex = metaKeys.findIndex((key) => key.source === USERFUNCTIONS_PRESET_META_KEY);
105
+ if (oldPresetIndex >= 0) {
106
+ metaKeys.splice(oldPresetIndex, 1);
107
+ }
108
+ if (template.presetId) {
109
+ metaKeys.push({ source: USERFUNCTIONS_PRESET_META_KEY, id: template.presetId });
110
+ }
111
+ }
112
+ };
113
+
96
114
  const handleDeploy = useCallback(async () => {
97
115
  if (!script.source || !identity || !space) {
98
116
  return;
@@ -104,11 +122,7 @@ export const ScriptEditor = ({ env, script, role }: ScriptEditorProps) => {
104
122
  const existingFunctionId = existingFunctionUrl?.split('/').at(-1);
105
123
  const ownerDid = (existingFunctionUrl?.split('/').at(-2) as DID) ?? publicKeyToDid(identity.identityKey);
106
124
 
107
- const bundler = new Bundler({
108
- platform: 'browser',
109
- sandboxedModules: [],
110
- remoteModules: {},
111
- });
125
+ const bundler = new Bundler({ platform: 'browser', sandboxedModules: [], remoteModules: {} });
112
126
  const buildResult = await bundler.bundle(script.source.content);
113
127
  if (buildResult.error || !buildResult.bundle) {
114
128
  throw buildResult.error;
@@ -124,15 +138,18 @@ export const ScriptEditor = ({ env, script, role }: ScriptEditorProps) => {
124
138
  if (result !== 'success' || functionId === undefined || functionVersionNumber === undefined) {
125
139
  throw new Error(errorMessage);
126
140
  }
141
+
127
142
  log.info('function uploaded', { functionId, functionVersionNumber });
128
143
  if (fn) {
129
144
  fn.version = functionVersionNumber;
130
145
  }
146
+
131
147
  const deployedFunction =
132
148
  fn ?? space.db.add(create(FunctionType, { version: functionVersionNumber, source: script }));
133
149
  const meta = getMeta(deployedFunction);
134
- setUserFunctionUrlInMetadata(meta, `/${ownerDid}/${functionId}`);
135
150
  script.changed = false;
151
+ setUserFunctionUrlInMetadata(meta, `/${ownerDid}/${functionId}`);
152
+ setView('split');
136
153
  } catch (err: any) {
137
154
  log.catch(err);
138
155
  setError(t('upload failed label'));
@@ -155,33 +172,32 @@ export const ScriptEditor = ({ env, script, role }: ScriptEditorProps) => {
155
172
  }, [existingFunctionUrl, space]);
156
173
 
157
174
  return (
158
- <div
159
- role='none'
160
- className={mx(role === 'article' && 'row-span-2', 'flex flex-col is-full bs-full overflow-hidden')}
161
- >
162
- <TypescriptEditor
163
- id={script.id}
164
- env={env}
165
- initialValue={initialValue}
166
- extensions={extensions}
167
- className='flex is-full bs-full overflow-hidden border-b border-separator'
168
- />
169
-
175
+ <div role='none' className={mx('flex flex-col w-full overflow-hidden divide-y divide-separator', classNames)}>
170
176
  <Toolbar
171
177
  deployed={Boolean(existingFunctionUrl) && !script.changed}
172
178
  functionUrl={functionUrl}
173
179
  error={error}
174
- showPanel={showPanel}
180
+ view={view}
181
+ templates={templates}
175
182
  onDeploy={handleDeploy}
176
183
  onFormat={handleFormat}
177
- onTogglePanel={async () => setShowPanel((showDetails) => !showDetails)}
184
+ onViewChange={setView}
185
+ onTemplateSelect={handleTemplateChange}
178
186
  />
179
187
 
180
- {showPanel && (
188
+ {view !== 'preview' && (
189
+ <TypescriptEditor
190
+ id={script.id}
191
+ env={env}
192
+ initialValue={initialValue}
193
+ extensions={extensions}
194
+ className='flex is-full bs-full overflow-hidden ch-focus-ring-inset-over-all'
195
+ />
196
+ )}
197
+
198
+ {view !== 'editor' && (
181
199
  <DebugPanel functionUrl={functionUrl} binding={fn?.binding} onBindingChange={handleBindingChange} />
182
200
  )}
183
201
  </div>
184
202
  );
185
203
  };
186
-
187
- export default ScriptEditor;
@@ -0,0 +1,47 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { SettingsValue } from '@dxos/plugin-settings';
8
+ import { type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
9
+ import { useClient } from '@dxos/react-client';
10
+ import { Button, useTranslation } from '@dxos/react-ui';
11
+
12
+ import { SCRIPT_PLUGIN } from '../../meta';
13
+ import { type ScriptSettingsProps } from '../../types';
14
+
15
+ export const ScriptSettings = ({ settings }: { settings: ScriptSettingsProps }) => {
16
+ const { t } = useTranslation(SCRIPT_PLUGIN);
17
+ const client = useClient();
18
+
19
+ // TODO(burdon): Check token.
20
+ const handleAuthenticate = async () => {
21
+ const { identityKey } = client.halo.identity.get()!;
22
+ await client.halo.writeCredentials([
23
+ {
24
+ issuer: identityKey,
25
+ issuanceDate: new Date(),
26
+ subject: {
27
+ id: identityKey,
28
+ assertion: {
29
+ '@type': 'dxos.halo.credentials.ServiceAccess',
30
+ serverName: 'hub.dxos.network',
31
+ serverKey: identityKey,
32
+ identityKey,
33
+ capabilities: ['composer:beta'],
34
+ },
35
+ },
36
+ } satisfies Credential,
37
+ ]);
38
+ };
39
+
40
+ return (
41
+ <>
42
+ <SettingsValue label={t('authenticate action label')}>
43
+ <Button onClick={handleAuthenticate}>{t('authenticate button label')}</Button>
44
+ </SettingsValue>
45
+ </>
46
+ );
47
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './ScriptSettings';
@@ -0,0 +1,26 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
8
+
9
+ import { Toolbar } from './Toolbar';
10
+ import { templates } from '../../templates';
11
+
12
+ export default {
13
+ title: 'plugin-script/Toolbar',
14
+ component: Toolbar,
15
+ decorators: [withTheme, withLayout({ tooltips: true })],
16
+ };
17
+
18
+ export const Default = {
19
+ args: {
20
+ binding: 'example',
21
+ deployed: true,
22
+ templates,
23
+ onFormat: () => console.log('Format'),
24
+ onTogglePanel: () => {},
25
+ },
26
+ };