@dxos/plugin-automation 0.8.4-main.bc674ce → 0.8.4-main.bcb3aa67d6

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 (259) hide show
  1. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  2. package/dist/lib/browser/chunk-NQY2QL47.mjs +44 -0
  3. package/dist/lib/browser/chunk-NQY2QL47.mjs.map +7 -0
  4. package/dist/lib/browser/{chunk-JOXPQ27I.mjs → chunk-WZKRIDQ6.mjs} +9 -38
  5. package/dist/lib/browser/chunk-WZKRIDQ6.mjs.map +7 -0
  6. package/dist/lib/browser/cli/index.mjs +96 -81
  7. package/dist/lib/browser/cli/index.mjs.map +3 -3
  8. package/dist/lib/browser/create-trigger-from-template-J2Z7AAHV.mjs +77 -0
  9. package/dist/lib/browser/create-trigger-from-template-J2Z7AAHV.mjs.map +7 -0
  10. package/dist/lib/browser/hooks/index.mjs +110 -6
  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-POUAOKR5.mjs} +9 -37
  20. package/dist/lib/node-esm/chunk-POUAOKR5.mjs.map +7 -0
  21. package/dist/lib/node-esm/chunk-Z6J7TDVZ.mjs +45 -0
  22. package/dist/lib/node-esm/chunk-Z6J7TDVZ.mjs.map +7 -0
  23. package/dist/lib/node-esm/cli/index.mjs +96 -81
  24. package/dist/lib/node-esm/cli/index.mjs.map +3 -3
  25. package/dist/lib/node-esm/create-trigger-from-template-TRSHHYEB.mjs +78 -0
  26. package/dist/lib/node-esm/create-trigger-from-template-TRSHHYEB.mjs.map +7 -0
  27. package/dist/lib/node-esm/hooks/index.mjs +110 -6
  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 +90 -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 +3 -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 +3 -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 +4 -3
  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 +16 -14
  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 +5 -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/compute-runtime.ts → compute-runtime.ts} +68 -21
  124. package/src/capabilities/index.ts +10 -4
  125. package/src/capabilities/operation-handler.ts +16 -0
  126. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +17 -20
  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 +12 -12
  133. package/src/cli/commands/trigger/update/subscription.ts +12 -11
  134. package/src/cli/commands/trigger/update/timer.ts +12 -11
  135. package/src/cli/commands/trigger/util.ts +43 -29
  136. package/src/cli/plugin.ts +7 -6
  137. package/src/components/AutomationPanel/AutomationPanel.stories.tsx +9 -7
  138. package/src/components/AutomationPanel/AutomationPanel.tsx +147 -77
  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 +52 -9
  145. package/src/components/TriggerEditor/TriggerEditor.tsx +46 -17
  146. package/src/components/index.ts +1 -2
  147. package/src/containers/AutomationSettings/AutomationSettings.tsx +27 -0
  148. package/src/containers/AutomationSettings/index.ts +7 -0
  149. package/src/containers/FunctionsContainer/FunctionsContainer.tsx +33 -0
  150. package/src/containers/FunctionsContainer/index.ts +7 -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 +15 -0
  156. package/src/hooks/useComputeRuntimeCallback.ts +6 -6
  157. package/src/hooks/useComputeRuntimeService.ts +22 -0
  158. package/src/hooks/useTriggerRuntimeControls.ts +22 -8
  159. package/src/index.ts +2 -6
  160. package/src/meta.ts +1 -1
  161. package/src/operations/create-trigger-from-template.ts +74 -0
  162. package/src/operations/definitions.ts +27 -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 +18 -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/operation-resolver/index.ts +0 -7
  252. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -79
  253. package/src/capabilities/react-surface/index.ts +0 -7
  254. package/src/components/AutomationSettings.tsx +0 -30
  255. package/src/components/FunctionsContainer.tsx +0 -36
  256. /package/dist/lib/browser/{AutomationPanel-FAS6ADCW.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
  257. /package/dist/lib/{browser/FunctionsPanel-ZX4J75UM.mjs.map → node-esm/chunk-HSLMI22Q.mjs.map} +0 -0
  258. /package/dist/types/src/{components → containers/TriggerSettings}/TriggerSettings.d.ts +0 -0
  259. /package/src/capabilities/{compute-runtime/index.ts → node.ts} +0 -0
@@ -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,9 +4,11 @@
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';
11
+ import { Operation } from '@dxos/operation';
10
12
  import { invariant } from '@dxos/invariant';
11
13
  import { faker } from '@dxos/random';
12
14
  import { useQuery } from '@dxos/react-client/echo';
@@ -14,9 +16,9 @@ import { TestSchema, useClientStory, withClientProvider } from '@dxos/react-clie
14
16
  import { useAsyncEffect } from '@dxos/react-ui';
15
17
  import { withLayout, withTheme } from '@dxos/react-ui/testing';
16
18
  import { translations as formTranslations } from '@dxos/react-ui-form';
17
- import { Employer, Organization, Person, Project } from '@dxos/types';
19
+ import { Employer, Organization, Person, Pipeline } from '@dxos/types';
18
20
 
19
- import { functions } from '../../testing';
21
+ import { functions } from '#testing';
20
22
  import { translations } from '../../translations';
21
23
 
22
24
  import { TriggerEditor, type TriggerEditorProps } from './TriggerEditor';
@@ -25,7 +27,7 @@ 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,7 +92,7 @@ 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.
@@ -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, (obj) => {
45
+ Object.assign(obj, 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,27 @@
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 { AutomationPanel, type AutomationPanelProps } from '../../components/AutomationPanel';
11
+ import { meta } from '#meta';
12
+ import { TriggersSettings } from '../TriggerSettings';
13
+
14
+ export const AutomationSettings = (props: AutomationPanelProps) => {
15
+ const { t } = useTranslation(meta.id);
16
+ return (
17
+ <Settings.Viewport>
18
+ <Settings.Section
19
+ title={t('automation-verbose.label', { ns: meta.id })}
20
+ description={t('automation.description', { ns: meta.id })}
21
+ >
22
+ <AutomationPanel {...props} />
23
+ <TriggersSettings db={props.space.db} />
24
+ </Settings.Section>
25
+ </Settings.Viewport>
26
+ );
27
+ };
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { AutomationSettings } from './AutomationSettings';
6
+
7
+ export default AutomationSettings;
@@ -0,0 +1,33 @@
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 { FunctionsPanel } from '../../components/FunctionsPanel';
12
+ import { FunctionsRegistry } from '../../components/FunctionsRegistry';
13
+ import { meta } from '#meta';
14
+
15
+ export const FunctionsContainer = ({ space }: { space: Space }) => {
16
+ const { t } = useTranslation(meta.id);
17
+ return (
18
+ <Settings.Viewport>
19
+ <Settings.Section
20
+ title={t('functions-verbose.label', { ns: meta.id })}
21
+ description={t('functions.description', { ns: meta.id })}
22
+ >
23
+ <FunctionsPanel space={space} />
24
+ </Settings.Section>
25
+ <Settings.Section
26
+ title={t('functions-registry-verbose.label', { ns: meta.id })}
27
+ description={t('functions-registry.description', { ns: meta.id })}
28
+ >
29
+ <FunctionsRegistry space={space} />
30
+ </Settings.Section>
31
+ </Settings.Viewport>
32
+ );
33
+ };
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { FunctionsContainer } from './FunctionsContainer';
6
+
7
+ export default 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,15 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useCapability } from '@dxos/app-framework/ui';
6
+ import { AutomationCapabilities } from '../types';
7
+ import { SpaceId } from '@dxos/keys';
8
+
9
+ /**
10
+ * Resolves the compute runtime for a space.
11
+ */
12
+ export const useComputeRuntime = (id: SpaceId | undefined): AutomationCapabilities.ComputeRuntime | undefined => {
13
+ const computeRuntime = useCapability(AutomationCapabilities.ComputeRuntime);
14
+ return id !== undefined ? computeRuntime.getRuntime(id) : undefined;
15
+ };
@@ -7,12 +7,13 @@ import * as Effect from 'effect/Effect';
7
7
  import * as Exit from 'effect/Exit';
8
8
  import { type DependencyList, useCallback } from 'react';
9
9
 
10
- import { useCapability } from '@dxos/app-framework/react';
11
10
  import { type Key } from '@dxos/echo';
12
- import { type FunctionDefinition, FunctionInvocationService, TracingService } from '@dxos/functions';
11
+ import { FunctionInvocationService, TracingService } from '@dxos/functions';
12
+ import { type Operation } from '@dxos/operation';
13
13
  import { log } from '@dxos/log';
14
14
 
15
- import { AutomationCapabilities } from '../types';
15
+ import { AutomationCapabilities } from '#types';
16
+ import { useComputeRuntime } from './useComputeRuntime';
16
17
 
17
18
  /**
18
19
  * Create an effectful function that has access to compute services
@@ -23,8 +24,7 @@ export const useComputeRuntimeCallback = <T>(
23
24
  fn: () => Effect.Effect<T, any, AutomationCapabilities.ComputeServices>,
24
25
  deps?: DependencyList,
25
26
  ): (() => Promise<T>) => {
26
- const computeRuntime = useCapability(AutomationCapabilities.ComputeRuntime);
27
- const runtime = id !== undefined ? computeRuntime.getRuntime(id) : undefined;
27
+ const runtime = useComputeRuntime(id);
28
28
 
29
29
  return useCallback(() => {
30
30
  if (!runtime) {
@@ -36,7 +36,7 @@ export const useComputeRuntimeCallback = <T>(
36
36
  };
37
37
 
38
38
  // TODO(wittjosiah): Function invoking should automatically be traced (DX-647).
39
- export const invokeFunctionWithTracing = <I, O>(functionDef: FunctionDefinition<I, O>, inputData: I) =>
39
+ export const invokeFunctionWithTracing = <I, O>(functionDef: Operation.Definition<I, O, any>, inputData: I) =>
40
40
  Effect.gen(function* () {
41
41
  const tracer = yield* TracingService;
42
42
  const trace = yield* tracer.traceInvocationStart({
@@ -0,0 +1,22 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { SpaceId } from '@dxos/keys';
6
+ import { AutomationCapabilities } from '../types';
7
+ import * as Context from 'effect/Context';
8
+ import { useComputeRuntime } from './useComputeRuntime';
9
+ import { use } from 'react';
10
+ import { unwrapExit } from '@dxos/effect';
11
+ import { useMemo } from 'react';
12
+
13
+ export const useComputeRuntimeService = <T extends Context.Tag<any, any>>(
14
+ tag: T,
15
+ spaceId?: SpaceId,
16
+ ): (Context.Tag.Service<T> & AutomationCapabilities.ComputeRuntime) | undefined => {
17
+ const runtime = useComputeRuntime(spaceId);
18
+ if (!runtime) {
19
+ return undefined;
20
+ }
21
+ return unwrapExit(use(useMemo(() => runtime.runPromiseExit(tag), [runtime, tag])));
22
+ };
@@ -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
  };
package/src/index.ts CHANGED
@@ -2,9 +2,5 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export * from './components';
6
- export * from './meta';
7
- export * from './hooks';
8
- export * from './types';
9
-
10
- export * from './AutomationPlugin';
5
+ export { AutomationPlugin } from './AutomationPlugin';
6
+ export { meta } from './meta';
package/src/meta.ts CHANGED
@@ -6,7 +6,7 @@ import { type Plugin } from '@dxos/app-framework';
6
6
  import { trim } from '@dxos/util';
7
7
 
8
8
  export const meta: Plugin.Meta = {
9
- id: 'dxos.org/plugin/automation',
9
+ id: 'org.dxos.plugin.automation',
10
10
  name: 'Automation',
11
11
  description: trim`
12
12
  Workflow automation engine that triggers custom actions based on object events and conditions.
@@ -0,0 +1,74 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { LayoutOperation, getSpacePath } from '@dxos/app-toolkit';
8
+ import { Obj, Ref } from '@dxos/echo';
9
+ import { Script, Trigger } from '@dxos/functions';
10
+ import { type DXN } from '@dxos/keys';
11
+ import { Operation } from '@dxos/operation';
12
+ import { SpaceOperation } from '@dxos/plugin-space/operations';
13
+ import { Filter } from '@dxos/react-client/echo';
14
+
15
+ import { meta } from '#meta';
16
+ import { CreateTriggerFromTemplate } from './definitions';
17
+
18
+ const handler: Operation.WithHandler<typeof CreateTriggerFromTemplate> = CreateTriggerFromTemplate.pipe(
19
+ Operation.withHandler(
20
+ Effect.fnUntraced(function* ({ db, template, enabled = false, scriptName, input }) {
21
+ const trigger = Trigger.make({ enabled, input });
22
+
23
+ // TODO(wittjosiah): Factor out function lookup by script name?
24
+ if (scriptName) {
25
+ const scripts = yield* Effect.promise(() => db.query(Filter.type(Script.Script, { name: scriptName })).run());
26
+ const [script] = scripts;
27
+ if (script) {
28
+ const functions = yield* Effect.promise(() =>
29
+ db.query(Filter.type(Operation.PersistentOperation, { source: Ref.make(script) })).run(),
30
+ );
31
+ const [fn] = functions;
32
+ if (fn) {
33
+ Obj.change(trigger, (obj) => {
34
+ obj.function = Ref.make(fn);
35
+ });
36
+ }
37
+ }
38
+ }
39
+
40
+ switch (template.type) {
41
+ case 'timer': {
42
+ Obj.change(trigger, (obj) => {
43
+ obj.spec = { kind: 'timer', cron: template.cron };
44
+ });
45
+ break;
46
+ }
47
+ case 'queue': {
48
+ Obj.change(trigger, (obj) => {
49
+ obj.spec = {
50
+ kind: 'queue',
51
+ queue: (template.queueDXN as DXN).toString(),
52
+ };
53
+ });
54
+ break;
55
+ }
56
+ default: {
57
+ break;
58
+ }
59
+ }
60
+
61
+ yield* Operation.invoke(SpaceOperation.AddObject, {
62
+ object: trigger,
63
+ target: db,
64
+ hidden: true,
65
+ });
66
+ yield* Operation.invoke(LayoutOperation.Open, {
67
+ subject: [`${getSpacePath(db.spaceId)}/settings/${meta.id}.automations`],
68
+ workspace: getSpacePath(db.spaceId),
69
+ });
70
+ }),
71
+ ),
72
+ );
73
+
74
+ export default handler;