@dxos/plugin-automation 0.8.4-main.9735255 → 0.8.4-main.9be5663bfe

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 (261) hide show
  1. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  2. package/dist/lib/browser/chunk-POEIL4RN.mjs +44 -0
  3. package/dist/lib/browser/chunk-POEIL4RN.mjs.map +7 -0
  4. package/dist/lib/browser/{chunk-JOXPQ27I.mjs → chunk-WQLEMRPU.mjs} +9 -38
  5. package/dist/lib/browser/chunk-WQLEMRPU.mjs.map +7 -0
  6. package/dist/lib/browser/cli/index.mjs +122 -107
  7. package/dist/lib/browser/cli/index.mjs.map +3 -3
  8. package/dist/lib/browser/create-trigger-from-template-JZ62EZTB.mjs +77 -0
  9. package/dist/lib/browser/create-trigger-from-template-JZ62EZTB.mjs.map +7 -0
  10. package/dist/lib/browser/hooks/index.mjs +79 -7
  11. package/dist/lib/browser/hooks/index.mjs.map +4 -4
  12. package/dist/lib/browser/index.mjs +60 -92
  13. package/dist/lib/browser/index.mjs.map +4 -4
  14. package/dist/lib/browser/meta.json +1 -1
  15. package/dist/lib/browser/operations/index.mjs +14 -0
  16. package/dist/lib/browser/operations/index.mjs.map +7 -0
  17. package/dist/lib/browser/types/index.mjs +4 -4
  18. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  19. package/dist/lib/node-esm/{chunk-RX52VKI2.mjs → chunk-JWZAVQLF.mjs} +9 -37
  20. package/dist/lib/node-esm/chunk-JWZAVQLF.mjs.map +7 -0
  21. package/dist/lib/node-esm/chunk-SP3P4OUI.mjs +45 -0
  22. package/dist/lib/node-esm/chunk-SP3P4OUI.mjs.map +7 -0
  23. package/dist/lib/node-esm/cli/index.mjs +122 -107
  24. package/dist/lib/node-esm/cli/index.mjs.map +3 -3
  25. package/dist/lib/node-esm/create-trigger-from-template-224Z7WJI.mjs +78 -0
  26. package/dist/lib/node-esm/create-trigger-from-template-224Z7WJI.mjs.map +7 -0
  27. package/dist/lib/node-esm/hooks/index.mjs +79 -7
  28. package/dist/lib/node-esm/hooks/index.mjs.map +4 -4
  29. package/dist/lib/node-esm/index.mjs +60 -92
  30. package/dist/lib/node-esm/index.mjs.map +4 -4
  31. package/dist/lib/node-esm/meta.json +1 -1
  32. package/dist/lib/node-esm/operations/index.mjs +15 -0
  33. package/dist/lib/node-esm/operations/index.mjs.map +7 -0
  34. package/dist/lib/node-esm/types/index.mjs +4 -4
  35. package/dist/types/src/AutomationPlugin.d.ts.map +1 -1
  36. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  37. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  38. package/dist/types/src/capabilities/compute-runtime.d.ts +6 -0
  39. package/dist/types/src/capabilities/compute-runtime.d.ts.map +1 -0
  40. package/dist/types/src/capabilities/index.d.ts +6 -4
  41. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  42. package/dist/types/src/capabilities/node.d.ts +3 -0
  43. package/dist/types/src/capabilities/node.d.ts.map +1 -0
  44. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  45. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  46. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  47. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  48. package/dist/types/src/cli/commands/trigger/create/index.d.ts +1 -1
  49. package/dist/types/src/cli/commands/trigger/create/queue.d.ts +1 -1
  50. package/dist/types/src/cli/commands/trigger/create/queue.d.ts.map +1 -1
  51. package/dist/types/src/cli/commands/trigger/create/subscription.d.ts +1 -1
  52. package/dist/types/src/cli/commands/trigger/create/subscription.d.ts.map +1 -1
  53. package/dist/types/src/cli/commands/trigger/create/timer.d.ts +1 -1
  54. package/dist/types/src/cli/commands/trigger/create/timer.d.ts.map +1 -1
  55. package/dist/types/src/cli/commands/trigger/list.d.ts +1 -1
  56. package/dist/types/src/cli/commands/trigger/list.d.ts.map +1 -1
  57. package/dist/types/src/cli/commands/trigger/remove.d.ts +1 -1
  58. package/dist/types/src/cli/commands/trigger/update/queue.d.ts.map +1 -1
  59. package/dist/types/src/cli/commands/trigger/update/subscription.d.ts.map +1 -1
  60. package/dist/types/src/cli/commands/trigger/update/timer.d.ts.map +1 -1
  61. package/dist/types/src/cli/commands/trigger/util.d.ts +2 -2
  62. package/dist/types/src/cli/commands/trigger/util.d.ts.map +1 -1
  63. package/dist/types/src/cli/plugin.d.ts.map +1 -1
  64. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +3 -4
  65. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +1 -1
  66. package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts +28 -30
  67. package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts.map +1 -1
  68. package/dist/types/src/components/FunctionsPanel/FunctionsPanel.d.ts.map +1 -1
  69. package/dist/types/src/components/FunctionsRegistry/FunctionsRegistry.d.ts.map +1 -1
  70. package/dist/types/src/components/FunctionsRegistry/index.d.ts +3 -1
  71. package/dist/types/src/components/FunctionsRegistry/index.d.ts.map +1 -1
  72. package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts +2 -2
  73. package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts.map +1 -1
  74. package/dist/types/src/components/TriggerEditor/SpecSelector.d.ts.map +1 -1
  75. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
  76. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts +91 -91
  77. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -1
  78. package/dist/types/src/components/index.d.ts +3 -4
  79. package/dist/types/src/components/index.d.ts.map +1 -1
  80. package/dist/types/src/containers/AutomationSettings/AutomationSettings.d.ts +4 -0
  81. package/dist/types/src/containers/AutomationSettings/AutomationSettings.d.ts.map +1 -0
  82. package/dist/types/src/containers/AutomationSettings/index.d.ts +2 -0
  83. package/dist/types/src/containers/AutomationSettings/index.d.ts.map +1 -0
  84. package/dist/types/src/{components → containers/FunctionsContainer}/FunctionsContainer.d.ts +0 -1
  85. package/dist/types/src/containers/FunctionsContainer/FunctionsContainer.d.ts.map +1 -0
  86. package/dist/types/src/containers/FunctionsContainer/index.d.ts +2 -0
  87. package/dist/types/src/containers/FunctionsContainer/index.d.ts.map +1 -0
  88. package/dist/types/src/containers/TriggerSettings/TriggerSettings.d.ts.map +1 -0
  89. package/dist/types/src/containers/TriggerSettings/index.d.ts +3 -0
  90. package/dist/types/src/containers/TriggerSettings/index.d.ts.map +1 -0
  91. package/dist/types/src/containers/index.d.ts +5 -0
  92. package/dist/types/src/containers/index.d.ts.map +1 -0
  93. package/dist/types/src/hooks/index.d.ts +2 -0
  94. package/dist/types/src/hooks/index.d.ts.map +1 -1
  95. package/dist/types/src/hooks/useComputeRuntime.d.ts +7 -0
  96. package/dist/types/src/hooks/useComputeRuntime.d.ts.map +1 -0
  97. package/dist/types/src/hooks/useComputeRuntimeCallback.d.ts +1 -4
  98. package/dist/types/src/hooks/useComputeRuntimeCallback.d.ts.map +1 -1
  99. package/dist/types/src/hooks/useComputeRuntimeService.d.ts +5 -0
  100. package/dist/types/src/hooks/useComputeRuntimeService.d.ts.map +1 -0
  101. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts +2 -1
  102. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts.map +1 -1
  103. package/dist/types/src/index.d.ts +2 -5
  104. package/dist/types/src/index.d.ts.map +1 -1
  105. package/dist/types/src/operations/create-trigger-from-template.d.ts +5 -0
  106. package/dist/types/src/operations/create-trigger-from-template.d.ts.map +1 -0
  107. package/dist/types/src/operations/definitions.d.ts +19 -0
  108. package/dist/types/src/operations/definitions.d.ts.map +1 -0
  109. package/dist/types/src/operations/index.d.ts +4 -0
  110. package/dist/types/src/operations/index.d.ts.map +1 -0
  111. package/dist/types/src/testing/test-functions.d.ts +2 -0
  112. package/dist/types/src/testing/test-functions.d.ts.map +1 -1
  113. package/dist/types/src/translations.d.ts +29 -31
  114. package/dist/types/src/translations.d.ts.map +1 -1
  115. package/dist/types/src/types/capabilities.d.ts +6 -3
  116. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  117. package/dist/types/src/types/schema.d.ts +9 -30
  118. package/dist/types/src/types/schema.d.ts.map +1 -1
  119. package/dist/types/tsconfig.tsbuildinfo +1 -1
  120. package/package.json +73 -46
  121. package/src/AutomationPlugin.tsx +13 -10
  122. package/src/capabilities/app-graph-builder.ts +62 -0
  123. package/src/capabilities/compute-runtime.ts +248 -0
  124. package/src/capabilities/index.ts +10 -4
  125. package/src/capabilities/operation-handler.ts +16 -0
  126. package/src/capabilities/react-surface.tsx +59 -0
  127. package/src/cli/commands/trigger/create/queue.ts +7 -6
  128. package/src/cli/commands/trigger/create/subscription.ts +7 -6
  129. package/src/cli/commands/trigger/create/timer.ts +7 -6
  130. package/src/cli/commands/trigger/list.ts +3 -2
  131. package/src/cli/commands/trigger/remove.ts +2 -2
  132. package/src/cli/commands/trigger/update/queue.ts +21 -21
  133. package/src/cli/commands/trigger/update/subscription.ts +20 -19
  134. package/src/cli/commands/trigger/update/timer.ts +21 -20
  135. package/src/cli/commands/trigger/util.ts +43 -29
  136. package/src/cli/plugin.ts +6 -6
  137. package/src/components/AutomationPanel/AutomationPanel.stories.tsx +10 -8
  138. package/src/components/AutomationPanel/AutomationPanel.tsx +160 -87
  139. package/src/components/FunctionsPanel/FunctionsPanel.tsx +37 -31
  140. package/src/components/FunctionsRegistry/FunctionsRegistry.tsx +27 -24
  141. package/src/components/FunctionsRegistry/index.ts +4 -1
  142. package/src/components/TriggerEditor/FunctionInputEditor.tsx +17 -8
  143. package/src/components/TriggerEditor/SpecSelector.tsx +12 -3
  144. package/src/components/TriggerEditor/TriggerEditor.stories.tsx +56 -13
  145. package/src/components/TriggerEditor/TriggerEditor.tsx +46 -17
  146. package/src/components/index.ts +1 -2
  147. package/src/containers/AutomationSettings/AutomationSettings.tsx +28 -0
  148. package/src/containers/AutomationSettings/index.ts +5 -0
  149. package/src/containers/FunctionsContainer/FunctionsContainer.tsx +34 -0
  150. package/src/containers/FunctionsContainer/index.ts +5 -0
  151. package/src/{components → containers/TriggerSettings}/TriggerSettings.tsx +8 -7
  152. package/src/containers/TriggerSettings/index.ts +6 -0
  153. package/src/containers/index.ts +9 -0
  154. package/src/hooks/index.ts +3 -0
  155. package/src/hooks/useComputeRuntime.ts +16 -0
  156. package/src/hooks/useComputeRuntimeCallback.ts +4 -39
  157. package/src/hooks/useComputeRuntimeService.ts +24 -0
  158. package/src/hooks/useTriggerRuntimeControls.ts +22 -8
  159. package/src/index.ts +2 -6
  160. package/src/meta.ts +2 -2
  161. package/src/operations/create-trigger-from-template.ts +75 -0
  162. package/src/operations/definitions.ts +28 -0
  163. package/src/operations/index.ts +9 -0
  164. package/src/testing/test-functions.ts +8 -5
  165. package/src/translations.ts +35 -36
  166. package/src/types/capabilities.ts +20 -6
  167. package/src/types/events.ts +2 -2
  168. package/src/types/schema.ts +3 -24
  169. package/dist/lib/browser/AutomationPanel-FAS6ADCW.mjs +0 -11
  170. package/dist/lib/browser/AutomationSettings-XN2OIYWL.mjs +0 -56
  171. package/dist/lib/browser/AutomationSettings-XN2OIYWL.mjs.map +0 -7
  172. package/dist/lib/browser/FunctionsContainer-6QLC7JP4.mjs +0 -129
  173. package/dist/lib/browser/FunctionsContainer-6QLC7JP4.mjs.map +0 -7
  174. package/dist/lib/browser/FunctionsPanel-ZX4J75UM.mjs +0 -10
  175. package/dist/lib/browser/app-graph-builder-LAQMEBMH.mjs +0 -84
  176. package/dist/lib/browser/app-graph-builder-LAQMEBMH.mjs.map +0 -7
  177. package/dist/lib/browser/chunk-54PANILA.mjs +0 -14
  178. package/dist/lib/browser/chunk-54PANILA.mjs.map +0 -7
  179. package/dist/lib/browser/chunk-BFUIVUQH.mjs +0 -102
  180. package/dist/lib/browser/chunk-BFUIVUQH.mjs.map +0 -7
  181. package/dist/lib/browser/chunk-BKFQBKYO.mjs +0 -8
  182. package/dist/lib/browser/chunk-BKFQBKYO.mjs.map +0 -7
  183. package/dist/lib/browser/chunk-JOXPQ27I.mjs.map +0 -7
  184. package/dist/lib/browser/chunk-PZNBEKO5.mjs +0 -17
  185. package/dist/lib/browser/chunk-PZNBEKO5.mjs.map +0 -7
  186. package/dist/lib/browser/chunk-QW3EM35H.mjs +0 -248
  187. package/dist/lib/browser/chunk-QW3EM35H.mjs.map +0 -7
  188. package/dist/lib/browser/chunk-RAF2FJST.mjs +0 -86
  189. package/dist/lib/browser/chunk-RAF2FJST.mjs.map +0 -7
  190. package/dist/lib/browser/chunk-YWLEY2FD.mjs +0 -200
  191. package/dist/lib/browser/chunk-YWLEY2FD.mjs.map +0 -7
  192. package/dist/lib/browser/compute-runtime-WTWLQ67J.mjs +0 -114
  193. package/dist/lib/browser/compute-runtime-WTWLQ67J.mjs.map +0 -7
  194. package/dist/lib/browser/operation-resolver-Q3MWOR7K.mjs +0 -82
  195. package/dist/lib/browser/operation-resolver-Q3MWOR7K.mjs.map +0 -7
  196. package/dist/lib/browser/react-surface-EV3AC62F.mjs +0 -65
  197. package/dist/lib/browser/react-surface-EV3AC62F.mjs.map +0 -7
  198. package/dist/lib/node-esm/AutomationPanel-B7NAGDFA.mjs +0 -12
  199. package/dist/lib/node-esm/AutomationPanel-B7NAGDFA.mjs.map +0 -7
  200. package/dist/lib/node-esm/AutomationSettings-M5PMZJ6P.mjs +0 -57
  201. package/dist/lib/node-esm/AutomationSettings-M5PMZJ6P.mjs.map +0 -7
  202. package/dist/lib/node-esm/FunctionsContainer-J4O2ULWR.mjs +0 -130
  203. package/dist/lib/node-esm/FunctionsContainer-J4O2ULWR.mjs.map +0 -7
  204. package/dist/lib/node-esm/FunctionsPanel-SS6GIVNU.mjs +0 -11
  205. package/dist/lib/node-esm/FunctionsPanel-SS6GIVNU.mjs.map +0 -7
  206. package/dist/lib/node-esm/app-graph-builder-4UCMXHYY.mjs +0 -85
  207. package/dist/lib/node-esm/app-graph-builder-4UCMXHYY.mjs.map +0 -7
  208. package/dist/lib/node-esm/chunk-2CKVH7JC.mjs +0 -201
  209. package/dist/lib/node-esm/chunk-2CKVH7JC.mjs.map +0 -7
  210. package/dist/lib/node-esm/chunk-5FXNN3MV.mjs +0 -19
  211. package/dist/lib/node-esm/chunk-5FXNN3MV.mjs.map +0 -7
  212. package/dist/lib/node-esm/chunk-7QRUPEHH.mjs +0 -16
  213. package/dist/lib/node-esm/chunk-7QRUPEHH.mjs.map +0 -7
  214. package/dist/lib/node-esm/chunk-HQLVREIX.mjs +0 -87
  215. package/dist/lib/node-esm/chunk-HQLVREIX.mjs.map +0 -7
  216. package/dist/lib/node-esm/chunk-K7GCM342.mjs +0 -10
  217. package/dist/lib/node-esm/chunk-K7GCM342.mjs.map +0 -7
  218. package/dist/lib/node-esm/chunk-KWKWOGS5.mjs +0 -103
  219. package/dist/lib/node-esm/chunk-KWKWOGS5.mjs.map +0 -7
  220. package/dist/lib/node-esm/chunk-LJAXQ6CX.mjs +0 -249
  221. package/dist/lib/node-esm/chunk-LJAXQ6CX.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-RX52VKI2.mjs.map +0 -7
  223. package/dist/lib/node-esm/compute-runtime-ZHROOBLY.mjs +0 -115
  224. package/dist/lib/node-esm/compute-runtime-ZHROOBLY.mjs.map +0 -7
  225. package/dist/lib/node-esm/operation-resolver-R5GA4YNO.mjs +0 -83
  226. package/dist/lib/node-esm/operation-resolver-R5GA4YNO.mjs.map +0 -7
  227. package/dist/lib/node-esm/react-surface-S6VZJCEZ.mjs +0 -66
  228. package/dist/lib/node-esm/react-surface-S6VZJCEZ.mjs.map +0 -7
  229. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +0 -6
  230. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
  231. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
  232. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
  233. package/dist/types/src/capabilities/compute-runtime/compute-runtime.d.ts +0 -6
  234. package/dist/types/src/capabilities/compute-runtime/compute-runtime.d.ts.map +0 -1
  235. package/dist/types/src/capabilities/compute-runtime/index.d.ts +0 -3
  236. package/dist/types/src/capabilities/compute-runtime/index.d.ts.map +0 -1
  237. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  238. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  239. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  240. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  241. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  242. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  243. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
  244. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  245. package/dist/types/src/components/AutomationSettings.d.ts +0 -5
  246. package/dist/types/src/components/AutomationSettings.d.ts.map +0 -1
  247. package/dist/types/src/components/FunctionsContainer.d.ts.map +0 -1
  248. package/dist/types/src/components/TriggerSettings.d.ts.map +0 -1
  249. package/src/capabilities/app-graph-builder/app-graph-builder.ts +0 -71
  250. package/src/capabilities/app-graph-builder/index.ts +0 -7
  251. package/src/capabilities/compute-runtime/compute-runtime.ts +0 -133
  252. package/src/capabilities/operation-resolver/index.ts +0 -7
  253. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -79
  254. package/src/capabilities/react-surface/index.ts +0 -7
  255. package/src/capabilities/react-surface/react-surface.tsx +0 -60
  256. package/src/components/AutomationSettings.tsx +0 -30
  257. package/src/components/FunctionsContainer.tsx +0 -36
  258. /package/dist/lib/browser/{AutomationPanel-FAS6ADCW.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
  259. /package/dist/lib/{browser/FunctionsPanel-ZX4J75UM.mjs.map → node-esm/chunk-HSLMI22Q.mjs.map} +0 -0
  260. /package/dist/types/src/{components → containers/TriggerSettings}/TriggerSettings.d.ts +0 -0
  261. /package/src/capabilities/{compute-runtime/index.ts → node.ts} +0 -0
@@ -5,17 +5,17 @@
5
5
  import type * as SchemaAST from 'effect/SchemaAST';
6
6
  import React, { useCallback, useMemo } from 'react';
7
7
 
8
- import { type Database, Ref, Type } from '@dxos/echo';
8
+ import { type Database, JsonSchema, Obj, Ref } from '@dxos/echo';
9
9
  import { type JsonPath } from '@dxos/echo/internal';
10
- import { type Function } from '@dxos/functions';
10
+ import { type Operation } from '@dxos/operation';
11
11
  import { useOnTransition, useTranslation } from '@dxos/react-ui';
12
12
  import { Form, type FormFieldStateProps, type FormRootProps, useFormValues } from '@dxos/react-ui-form';
13
13
 
14
- import { meta } from '../../meta';
14
+ import { meta } from '#meta';
15
15
 
16
16
  export type FunctionInputEditorProps = {
17
17
  type: SchemaAST.AST;
18
- functions: Function.Function[];
18
+ functions: Operation.PersistentOperation[];
19
19
  db?: Database.Database;
20
20
  } & FormFieldStateProps;
21
21
 
@@ -48,9 +48,12 @@ export const FunctionInputEditor = ({ type, functions, db, getValue, onValueChan
48
48
  );
49
49
 
50
50
  const inputSchema = useMemo(() => selectedFunction?.inputSchema, [selectedFunction]);
51
- const effectSchema = useMemo(() => (inputSchema ? Type.toEffectSchema(inputSchema) : undefined), [inputSchema]);
51
+ const effectSchema = useMemo(() => (inputSchema ? JsonSchema.toEffectSchema(inputSchema) : undefined), [inputSchema]);
52
52
  const propertyCount = inputSchema?.properties ? Object.keys(inputSchema.properties).length : 0;
53
- const values = useMemo(() => getValue() ?? {}, [getValue]);
53
+ const defaultValues = useMemo(() => {
54
+ const raw = getValue() ?? {};
55
+ return Obj.isObject(raw) ? { ...Obj.getSnapshot(raw) } : { ...raw };
56
+ }, [getValue]);
54
57
 
55
58
  const handleValuesChanged = useCallback<NonNullable<FormRootProps['onValuesChanged']>>(
56
59
  (values) => {
@@ -65,8 +68,14 @@ export const FunctionInputEditor = ({ type, functions, db, getValue, onValueChan
65
68
 
66
69
  return (
67
70
  <>
68
- <Form.Label label={t('function parameters label')} asChild />
69
- <Form.Root schema={effectSchema} values={values} db={db} onValuesChanged={handleValuesChanged}>
71
+ <Form.Label label={t('function-parameters.label')} asChild />
72
+ <Form.Root
73
+ key={selectedFunction.id}
74
+ schema={effectSchema}
75
+ defaultValues={defaultValues}
76
+ db={db}
77
+ onValuesChanged={handleValuesChanged}
78
+ >
70
79
  <Form.FieldSet />
71
80
  </Form.Root>
72
81
  </>
@@ -9,7 +9,7 @@ import { Trigger } from '@dxos/functions';
9
9
  import { useTranslation } from '@dxos/react-ui';
10
10
  import { type FormFieldComponentProps, SelectField, useFormFieldState } from '@dxos/react-ui-form';
11
11
 
12
- import { meta } from '../../meta';
12
+ import { meta } from '#meta';
13
13
 
14
14
  export type SpecSelectorProps = FormFieldComponentProps;
15
15
 
@@ -31,7 +31,7 @@ export const SpecSelector = (props: SpecSelectorProps) => {
31
31
  },
32
32
  };
33
33
  case 'queue':
34
- return { kind: 'queue', queue: 'dxn:' };
34
+ return { kind: 'queue', queue: 'dxn:queue:default' };
35
35
  case 'email':
36
36
  return { kind: 'email' };
37
37
  case 'webhook':
@@ -52,11 +52,20 @@ export const SpecSelector = (props: SpecSelectorProps) => {
52
52
  [props.type, specProps],
53
53
  );
54
54
 
55
+ const kindLabels: Record<string, string> = {
56
+ timer: t('trigger-type.timer.label'),
57
+ webhook: t('trigger-type.webhook.label'),
58
+ websocket: t('trigger-type.websocket.label'),
59
+ subscription: t('trigger-type.subscription.label'),
60
+ email: t('trigger-type.email.label'),
61
+ queue: t('trigger-type.queue.label'),
62
+ };
63
+
55
64
  const options = useMemo(
56
65
  () =>
57
66
  Trigger.Kinds.map((kind) => ({
58
67
  value: kind,
59
- label: t(`trigger type ${kind}`),
68
+ label: kindLabels[kind],
60
69
  })),
61
70
  [t],
62
71
  );
@@ -4,28 +4,30 @@
4
4
 
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useState } from 'react';
7
+ import { expect, userEvent, within } from 'storybook/test';
7
8
 
8
9
  import { Filter, Obj, Ref, Tag, Type } from '@dxos/echo';
9
- import { Function, Trigger } from '@dxos/functions';
10
+ import { Trigger } from '@dxos/functions';
10
11
  import { invariant } from '@dxos/invariant';
11
- import { faker } from '@dxos/random';
12
+ import { Operation } from '@dxos/operation';
13
+ import { random } from '@dxos/random';
12
14
  import { useQuery } from '@dxos/react-client/echo';
13
15
  import { TestSchema, useClientStory, withClientProvider } from '@dxos/react-client/testing';
14
16
  import { useAsyncEffect } from '@dxos/react-ui';
15
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
16
17
  import { translations as formTranslations } from '@dxos/react-ui-form';
17
- import { Employer, Organization, Person, Project } from '@dxos/types';
18
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
19
+ import { Employer, Organization, Person, Pipeline } from '@dxos/types';
18
20
 
19
- import { functions } from '../../testing';
20
- import { translations } from '../../translations';
21
+ import { functions } from '#testing';
21
22
 
23
+ import { translations } from '../../translations';
22
24
  import { TriggerEditor, type TriggerEditorProps } from './TriggerEditor';
23
25
 
24
26
  const types = [
25
27
  // TODO(burdon): Get label from annotation.
26
28
  { value: Organization.Organization.typename, label: 'Organization' },
27
29
  { value: Person.Person.typename, label: 'Person' },
28
- { value: Type.getTypename(Project.Project), label: 'Project' },
30
+ { value: Type.getTypename(Pipeline.Pipeline), label: 'Project' },
29
31
  { value: Employer.Employer.typename, label: 'Employer' },
30
32
  ];
31
33
 
@@ -39,7 +41,7 @@ const DefaultStory = (props: Partial<TriggerEditorProps>) => {
39
41
  return;
40
42
  }
41
43
 
42
- const functions = await space.db.query(Filter.type(Function.Function)).run();
44
+ const functions = await space.db.query(Filter.type(Operation.PersistentOperation)).run();
43
45
  const fn = functions.find((fn) => fn.name === 'example.com/function/forex');
44
46
  invariant(fn);
45
47
  const trigger = space.db.add(
@@ -72,16 +74,16 @@ const DefaultStory = (props: Partial<TriggerEditorProps>) => {
72
74
  };
73
75
 
74
76
  const meta = {
75
- title: 'plugins/plugin-automation/TriggerEditor',
77
+ title: 'plugins/plugin-automation/components/TriggerEditor',
76
78
  component: TriggerEditor as any,
77
79
  render: DefaultStory,
78
80
  decorators: [
79
- withTheme,
81
+ withTheme(),
80
82
  withLayout({ layout: 'column' }),
81
83
  withClientProvider({
82
84
  createIdentity: true,
83
85
  createSpace: true,
84
- types: [Tag.Tag, Function.Function, Trigger.Trigger, TestSchema.ContactType],
86
+ types: [Tag.Tag, Operation.PersistentOperation, Trigger.Trigger, TestSchema.ContactType],
85
87
  onCreateSpace: ({ space }) => {
86
88
  // Tags.
87
89
  ['Important', 'Investor', 'New'].forEach((label) => {
@@ -90,14 +92,14 @@ const meta = {
90
92
 
91
93
  // Functions.
92
94
  functions.forEach((fn) => {
93
- space.db.add(Function.make(fn));
95
+ space.db.add(Obj.make(Operation.PersistentOperation, { ...fn, version: fn.version ?? '0.1.0' }));
94
96
  });
95
97
 
96
98
  // Objects.
97
99
  Array.from({ length: 10 }).map(() => {
98
100
  return space.db.add(
99
101
  Obj.make(TestSchema.ContactType, {
100
- name: faker.person.fullName(),
102
+ name: random.person.fullName(),
101
103
  identifiers: [],
102
104
  }),
103
105
  );
@@ -122,3 +124,44 @@ export const ReadonlySpec: Story = {
122
124
  readonlySpec: true,
123
125
  },
124
126
  };
127
+
128
+ export const Spec: Story = {
129
+ play: async ({ canvasElement }) => {
130
+ const canvas = within(canvasElement);
131
+ const webhookText = await canvas.findByText('Webhook', {}, { timeout: 10_000 });
132
+ const combobox = webhookText.closest('[role="combobox"]') as HTMLElement;
133
+ await expect(combobox).not.toBeDisabled();
134
+
135
+ // Helper to switch to a kind via keyboard.
136
+ // TODO(wittjosiah): Radix Select in popper mode doesn't close on click.
137
+ // Use keyboard navigation: open, type first letter to jump, Enter to select.
138
+ const selectKind = async (combobox: HTMLElement, firstLetter: string) => {
139
+ combobox.focus();
140
+ await userEvent.keyboard('{Enter}');
141
+ await userEvent.keyboard(firstLetter);
142
+ await userEvent.keyboard('{Enter}');
143
+ };
144
+
145
+ // Timer — should show "Cron" field.
146
+ await selectKind(combobox, 't');
147
+ await expect(canvas.findByLabelText('Cron')).resolves.toBeInTheDocument();
148
+
149
+ // Email — no extra fields; Cron should be gone.
150
+ await selectKind(combobox, 'e');
151
+ await expect(combobox).not.toBeDisabled();
152
+ await expect(canvas.queryByLabelText('Cron')).not.toBeInTheDocument();
153
+
154
+ // Webhook — should show "Method" field.
155
+ await selectKind(combobox, 'w');
156
+ await expect(canvas.findByLabelText('Method')).resolves.toBeInTheDocument();
157
+
158
+ // Subscription — should show query editor.
159
+ await selectKind(combobox, 's');
160
+ await expect(combobox).not.toBeDisabled();
161
+ await expect(canvas.queryByLabelText('Method')).not.toBeInTheDocument();
162
+
163
+ // Feed — should show DXN field (the queue address). DXN is a combobox, not an input, so use getByText.
164
+ await selectKind(combobox, 'f');
165
+ await expect(canvas.findByText('DXN')).resolves.toBeInTheDocument();
166
+ },
167
+ };
@@ -5,8 +5,9 @@
5
5
  import React, { useCallback, useMemo } from 'react';
6
6
 
7
7
  import { ComputeGraph } from '@dxos/conductor';
8
- import { DXN, type Database, type Query } from '@dxos/echo';
9
- import { Function, Script, Trigger } from '@dxos/functions';
8
+ import { DXN, type Database, Entity, Feed, Obj, type Query } from '@dxos/echo';
9
+ import { Script, Trigger } from '@dxos/functions';
10
+ import { Operation } from '@dxos/operation';
10
11
  import { Filter, Ref, useQuery } from '@dxos/react-client/echo';
11
12
  import { Input } from '@dxos/react-ui';
12
13
  import { QueryForm, type QueryFormProps } from '@dxos/react-ui-components';
@@ -36,20 +37,31 @@ export type TriggerEditorProps = {
36
37
  Pick<FormRootProps<TriggerFormSchema>, 'onSave' | 'onCancel'>;
37
38
 
38
39
  export const TriggerEditor = ({ db, types, tags, readonlySpec, trigger, ...formProps }: TriggerEditorProps) => {
39
- const fieldMap = useCustomInputs({
40
- db,
41
- types,
42
- tags,
43
- readonlySpec,
44
- });
40
+ const fieldMap = useCustomInputs({ db, types, tags, readonlySpec });
41
+
42
+ const handleValuesChanged = useCallback(
43
+ (newValues: Partial<TriggerFormSchema>) => {
44
+ Obj.change(trigger, (trigger) => {
45
+ Object.assign(trigger, newValues);
46
+ });
47
+ },
48
+ [trigger],
49
+ );
50
+
51
+ const triggerSchema = useMemo(() => omitId(Trigger.Trigger), []);
52
+ const defaultValues = useMemo(() => {
53
+ const { id: _, ...values } = trigger;
54
+ return values;
55
+ }, [trigger]);
45
56
 
46
57
  return (
47
58
  <Form.Root<TriggerFormSchema>
48
59
  {...formProps}
49
- schema={omitId(Trigger.Trigger)}
50
- values={trigger}
51
60
  db={db}
61
+ schema={triggerSchema}
62
+ defaultValues={defaultValues}
52
63
  fieldMap={fieldMap}
64
+ onValuesChanged={handleValuesChanged}
53
65
  >
54
66
  <Form.Viewport>
55
67
  <Form.Content>
@@ -67,9 +79,10 @@ type UseCustomInputsProps = {
67
79
  } & Pick<QueryFormProps, 'types' | 'tags'>;
68
80
 
69
81
  const useCustomInputs = ({ db, readonlySpec, types, tags }: UseCustomInputsProps): FormFieldMap => {
70
- const functions = useQuery(db, Filter.type(Function.Function));
82
+ const functions = useQuery(db, Filter.type(Operation.PersistentOperation));
71
83
  const workflows = useQuery(db, Filter.type(ComputeGraph));
72
84
  const scripts = useQuery(db, Filter.type(Script.Script));
85
+ const feeds = useQuery(db, Filter.type(Feed.Feed));
73
86
 
74
87
  return useMemo(
75
88
  (): FormFieldMap => ({
@@ -105,11 +118,14 @@ const useCustomInputs = ({ db, readonlySpec, types, tags }: UseCustomInputsProps
105
118
  },
106
119
 
107
120
  // Spec selector.
108
- ['spec.kind' as const]: (props) => <SpecSelector {...props} readonly={readonlySpec} />,
121
+ 'spec.kind': (props) => <SpecSelector {...props} readonly={readonlySpec} />,
122
+
123
+ // Queue feed selector with parent labels.
124
+ 'spec.queue': (props) => <SelectField {...props} options={getFeedQueueOptions(feeds)} />,
109
125
 
110
126
  // TODO(wittjosiah): Copied from ViewEditor.
111
127
  // Query input editor.
112
- ['spec.query' as const]: (props) => {
128
+ 'spec.query': (props) => {
113
129
  const handleChange = useCallback(
114
130
  (query: Query.Any) => props.onValueChange(props.type, { ast: query.ast }),
115
131
  [props.type, props.onValueChange],
@@ -124,9 +140,9 @@ const useCustomInputs = ({ db, readonlySpec, types, tags }: UseCustomInputsProps
124
140
  },
125
141
 
126
142
  // Function input editor.
127
- ['input' as const]: (props) => <FunctionInputEditor {...props} functions={functions} db={db} />,
143
+ input: (props) => <FunctionInputEditor {...props} functions={functions} db={db} />,
128
144
  }),
129
- [workflows, scripts, functions, readonlySpec],
145
+ [workflows, scripts, functions, feeds, readonlySpec],
130
146
  );
131
147
  };
132
148
 
@@ -134,7 +150,20 @@ const getWorkflowOptions = (graphs: ComputeGraph[]) => {
134
150
  return graphs.map((graph) => ({ label: `compute-${graph.id}`, value: `dxn:echo:@:${graph.id}` }));
135
151
  };
136
152
 
137
- const getFunctionOptions = (scripts: Script.Script[], functions: Function.Function[]) => {
138
- const getLabel = (fn: Function.Function) => scripts.find((s) => fn.source?.target?.id === s.id)?.name ?? fn.name;
153
+ const getFunctionOptions = (scripts: Script.Script[], functions: Operation.PersistentOperation[]) => {
154
+ const getLabel = (fn: Operation.PersistentOperation) =>
155
+ scripts.find((s) => fn.source?.target?.id === s.id)?.name ?? fn.name;
139
156
  return functions.map((fn) => ({ label: getLabel(fn), value: `dxn:echo:@:${fn.id}` }));
140
157
  };
158
+
159
+ const getFeedQueueOptions = (feeds: Feed.Feed[]) => {
160
+ return feeds.flatMap((feed) => {
161
+ const queueDxn = Feed.getQueueDxn(feed);
162
+ if (!queueDxn) {
163
+ return [];
164
+ }
165
+ const parent = Obj.getParent(feed);
166
+ const label = parent ? Entity.getLabel(parent) : Entity.getLabel(feed);
167
+ return [{ label: label ?? feed.id, value: queueDxn.toString() }];
168
+ });
169
+ };
@@ -7,6 +7,5 @@ import { lazy } from 'react';
7
7
  export * from './TriggerEditor';
8
8
 
9
9
  export const AutomationPanel = lazy(() => import('./AutomationPanel'));
10
- export const AutomationSettings = lazy(() => import('./AutomationSettings'));
11
- export const FunctionsContainer = lazy(() => import('./FunctionsContainer'));
12
10
  export const FunctionsPanel = lazy(() => import('./FunctionsPanel'));
11
+ export const FunctionsRegistry = lazy(() => import('./FunctionsRegistry'));
@@ -0,0 +1,28 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { useTranslation } from '@dxos/react-ui';
8
+ import { Settings } from '@dxos/react-ui-form';
9
+
10
+ import { meta } from '#meta';
11
+
12
+ import { AutomationPanel, type AutomationPanelProps } from '../../components/AutomationPanel';
13
+ import { TriggersSettings } from '../TriggerSettings';
14
+
15
+ export const AutomationSettings = (props: AutomationPanelProps) => {
16
+ const { t } = useTranslation(meta.id);
17
+ return (
18
+ <Settings.Viewport>
19
+ <Settings.Section
20
+ title={t('automation-verbose.label', { ns: meta.id })}
21
+ description={t('automation.description', { ns: meta.id })}
22
+ >
23
+ <AutomationPanel {...props} />
24
+ <TriggersSettings db={props.space.db} />
25
+ </Settings.Section>
26
+ </Settings.Viewport>
27
+ );
28
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export { AutomationSettings as default } from './AutomationSettings';
@@ -0,0 +1,34 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { type Space } from '@dxos/react-client/echo';
8
+ import { useTranslation } from '@dxos/react-ui';
9
+ import { Settings } from '@dxos/react-ui-form';
10
+
11
+ import { meta } from '#meta';
12
+
13
+ import { FunctionsPanel } from '../../components/FunctionsPanel';
14
+ import { FunctionsRegistry } from '../../components/FunctionsRegistry';
15
+
16
+ export const FunctionsContainer = ({ space }: { space: Space }) => {
17
+ const { t } = useTranslation(meta.id);
18
+ return (
19
+ <Settings.Viewport>
20
+ <Settings.Section
21
+ title={t('functions-verbose.label', { ns: meta.id })}
22
+ description={t('functions.description', { ns: meta.id })}
23
+ >
24
+ <FunctionsPanel space={space} />
25
+ </Settings.Section>
26
+ <Settings.Section
27
+ title={t('functions-registry-verbose.label', { ns: meta.id })}
28
+ description={t('functions-registry.description', { ns: meta.id })}
29
+ >
30
+ <FunctionsRegistry space={space} />
31
+ </Settings.Section>
32
+ </Settings.Viewport>
33
+ );
34
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export { FunctionsContainer as default } from './FunctionsContainer';
@@ -6,20 +6,21 @@ import React from 'react';
6
6
 
7
7
  import { type Database } from '@dxos/echo';
8
8
  import { Input, useTranslation } from '@dxos/react-ui';
9
- import { ControlItemInput } from '@dxos/react-ui-form';
9
+ import { Settings } from '@dxos/react-ui-form';
10
10
 
11
- import { useTriggerRuntimeControls } from '../hooks';
12
- import { meta } from '../meta';
11
+ import { useTriggerRuntimeControls } from '#hooks';
12
+ import { meta } from '#meta';
13
13
 
14
14
  export const TriggersSettings = ({ db }: { db: Database.Database }) => {
15
- const { triggers, isRunning, start, stop } = useTriggerRuntimeControls(db);
15
+ const { state, start, stop } = useTriggerRuntimeControls(db);
16
+ const isRunning = state?.enabled ?? false;
16
17
  const { t } = useTranslation(meta.id);
17
18
 
18
19
  return (
19
- <div className='container-max-width grid grid-cols-1 md:grid-cols-[1fr_min-content]'>
20
- <ControlItemInput title={t('runtime label')} description={t('runtime description')}>
20
+ <div className='grid grid-cols-1 md:grid-cols-[1fr_min-content]'>
21
+ <Settings.Item title={t('runtime.label')} description={t('runtime.description')}>
21
22
  <Input.Switch classNames='justify-self-end' checked={isRunning} onCheckedChange={isRunning ? stop : start} />
22
- </ControlItemInput>
23
+ </Settings.Item>
23
24
  </div>
24
25
  );
25
26
  };
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export { TriggersSettings } from './TriggerSettings';
6
+ export { TriggersSettings as default } from './TriggerSettings';
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type ComponentType, lazy } from 'react';
6
+
7
+ export const AutomationSettings: ComponentType<any> = lazy(() => import('./AutomationSettings'));
8
+ export const FunctionsContainer: ComponentType<any> = lazy(() => import('./FunctionsContainer'));
9
+ export const TriggerSettings: ComponentType<any> = lazy(() => import('./TriggerSettings'));
@@ -2,5 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ // TODO(wittjosiah): Factor out.
5
6
  export * from './useComputeRuntimeCallback';
6
7
  export * from './useTriggerRuntimeControls';
8
+ export * from './useComputeRuntime';
9
+ export * from './useComputeRuntimeService';
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useCapability } from '@dxos/app-framework/ui';
6
+ import { SpaceId } from '@dxos/keys';
7
+
8
+ import { AutomationCapabilities } from '../types';
9
+
10
+ /**
11
+ * Resolves the compute runtime for a space.
12
+ */
13
+ export const useComputeRuntime = (id: SpaceId | undefined): AutomationCapabilities.ComputeRuntime | undefined => {
14
+ const computeRuntime = useCapability(AutomationCapabilities.ComputeRuntime);
15
+ return id !== undefined ? computeRuntime.getRuntime(id) : undefined;
16
+ };
@@ -2,17 +2,14 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import * as Cause from 'effect/Cause';
6
5
  import * as Effect from 'effect/Effect';
7
- import * as Exit from 'effect/Exit';
8
6
  import { type DependencyList, useCallback } from 'react';
9
7
 
10
- import { useCapability } from '@dxos/app-framework/react';
11
8
  import { type Key } from '@dxos/echo';
12
- import { type FunctionDefinition, FunctionInvocationService, TracingService } from '@dxos/functions';
13
- import { log } from '@dxos/log';
14
9
 
15
- import { AutomationCapabilities } from '../types';
10
+ import { AutomationCapabilities } from '#types';
11
+
12
+ import { useComputeRuntime } from './useComputeRuntime';
16
13
 
17
14
  /**
18
15
  * Create an effectful function that has access to compute services
@@ -23,8 +20,7 @@ export const useComputeRuntimeCallback = <T>(
23
20
  fn: () => Effect.Effect<T, any, AutomationCapabilities.ComputeServices>,
24
21
  deps?: DependencyList,
25
22
  ): (() => Promise<T>) => {
26
- const computeRuntime = useCapability(AutomationCapabilities.ComputeRuntime);
27
- const runtime = id !== undefined ? computeRuntime.getRuntime(id) : undefined;
23
+ const runtime = useComputeRuntime(id);
28
24
 
29
25
  return useCallback(() => {
30
26
  if (!runtime) {
@@ -34,34 +30,3 @@ export const useComputeRuntimeCallback = <T>(
34
30
  return runtime.runPromise(fn());
35
31
  }, [runtime, ...(deps ?? [])]);
36
32
  };
37
-
38
- // TODO(wittjosiah): Function invoking should automatically be traced (DX-647).
39
- export const invokeFunctionWithTracing = <I, O>(functionDef: FunctionDefinition<I, O>, inputData: I) =>
40
- Effect.gen(function* () {
41
- const tracer = yield* TracingService;
42
- const trace = yield* tracer.traceInvocationStart({
43
- target: undefined,
44
- payload: {
45
- data: {},
46
- },
47
- });
48
-
49
- // Invoke the function.
50
- const result = yield* FunctionInvocationService.invokeFunction(functionDef, inputData).pipe(
51
- Effect.provide(trace.invocationTraceQueue ? TracingService.layerInvocation(trace) : TracingService.layerNoop),
52
- Effect.exit,
53
- );
54
-
55
- if (Exit.isFailure(result)) {
56
- const error = Cause.prettyErrors(result.cause)[0];
57
- log.error(error.message, error.cause ?? error.stack);
58
- }
59
-
60
- yield* tracer.traceInvocationEnd({
61
- trace,
62
- // TODO(dmaretskyi): Might miss errors.
63
- exception: Exit.isFailure(result) ? Cause.prettyErrors(result.cause)[0] : undefined,
64
- });
65
-
66
- return result;
67
- });
@@ -0,0 +1,24 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Context from 'effect/Context';
6
+ import { use } from 'react';
7
+ import { useMemo } from 'react';
8
+
9
+ import { unwrapExit } from '@dxos/effect';
10
+ import { SpaceId } from '@dxos/keys';
11
+
12
+ import { AutomationCapabilities } from '../types';
13
+ import { useComputeRuntime } from './useComputeRuntime';
14
+
15
+ export const useComputeRuntimeService = <T extends Context.Tag<any, any>>(
16
+ tag: T,
17
+ spaceId?: SpaceId,
18
+ ): (Context.Tag.Service<T> & AutomationCapabilities.ComputeRuntime) | undefined => {
19
+ const runtime = useComputeRuntime(spaceId);
20
+ if (!runtime) {
21
+ return undefined;
22
+ }
23
+ return unwrapExit(use(useMemo(() => runtime.runPromiseExit(tag), [runtime, tag])));
24
+ };
@@ -2,19 +2,23 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { Atom, useAtomValue } from '@effect-atom/atom-react';
6
+ import type * as Context from 'effect/Context';
5
7
  import * as Effect from 'effect/Effect';
8
+ import { useEffect, useState } from 'react';
6
9
 
7
10
  import { type Database, Filter } from '@dxos/echo';
8
11
  import { Trigger } from '@dxos/functions';
9
- import { TriggerDispatcher } from '@dxos/functions-runtime';
12
+ import { TriggerDispatcher, type TriggerDispatcherState } from '@dxos/functions-runtime';
10
13
  import { useQuery } from '@dxos/react-client/echo';
11
- import { useAsyncState } from '@dxos/react-ui';
12
14
 
13
15
  import { useComputeRuntimeCallback } from './useComputeRuntimeCallback';
14
16
 
15
17
  interface TriggerRuntimeControls {
16
18
  triggers: Trigger.Trigger[];
17
- isRunning: boolean;
19
+
20
+ state: TriggerDispatcherState | undefined;
21
+
18
22
  start: () => void;
19
23
  stop: () => void;
20
24
  }
@@ -22,16 +26,27 @@ interface TriggerRuntimeControls {
22
26
  export const useTriggerRuntimeControls = (db: Database.Database | undefined): TriggerRuntimeControls => {
23
27
  const triggers = useQuery(db, Filter.type(Trigger.Trigger));
24
28
 
25
- const [isRunningState, setIsRunningState] = useAsyncState(
26
- useComputeRuntimeCallback(db?.spaceId, () => TriggerDispatcher.pipe(Effect.map((t) => t.running))),
29
+ const [dispatcher, setDispatcher] = useState<Context.Tag.Service<TriggerDispatcher> | undefined>(undefined);
30
+
31
+ const init = useComputeRuntimeCallback(
32
+ db?.spaceId,
33
+ Effect.fnUntraced(function* () {
34
+ const dispatcher = yield* TriggerDispatcher;
35
+ setDispatcher(dispatcher);
36
+ }),
27
37
  );
28
38
 
39
+ useEffect(() => {
40
+ void init();
41
+ }, []);
42
+
43
+ const state = useAtomValue(dispatcher?.state ?? Atom.make(undefined));
44
+
29
45
  const start = useComputeRuntimeCallback(
30
46
  db?.spaceId,
31
47
  Effect.fnUntraced(function* () {
32
48
  const dispatcher = yield* TriggerDispatcher;
33
49
  yield* dispatcher.start();
34
- setIsRunningState(true);
35
50
  }),
36
51
  );
37
52
 
@@ -40,13 +55,12 @@ export const useTriggerRuntimeControls = (db: Database.Database | undefined): Tr
40
55
  Effect.fnUntraced(function* () {
41
56
  const dispatcher = yield* TriggerDispatcher;
42
57
  yield* dispatcher.stop();
43
- setIsRunningState(false);
44
58
  }),
45
59
  );
46
60
 
47
61
  return {
48
62
  triggers,
49
- isRunning: isRunningState ?? false,
63
+ state,
50
64
  start: () => void start(),
51
65
  stop: () => void stop(),
52
66
  };