@dxos/plugin-automation 0.8.4-main.406dc2a → 0.8.4-main.422d1c7879

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 (287) hide show
  1. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  2. package/dist/lib/browser/chunk-LEN2XWRB.mjs +44 -0
  3. package/dist/lib/browser/chunk-LEN2XWRB.mjs.map +7 -0
  4. package/dist/lib/browser/chunk-VKSAIOAL.mjs +54 -0
  5. package/dist/lib/browser/chunk-VKSAIOAL.mjs.map +7 -0
  6. package/dist/lib/browser/cli/index.mjs +1110 -0
  7. package/dist/lib/browser/cli/index.mjs.map +7 -0
  8. package/dist/lib/browser/create-trigger-from-template-NH5EL6LB.mjs +71 -0
  9. package/dist/lib/browser/create-trigger-from-template-NH5EL6LB.mjs.map +7 -0
  10. package/dist/lib/browser/hooks/index.mjs +81 -6
  11. package/dist/lib/browser/hooks/index.mjs.map +4 -4
  12. package/dist/lib/browser/index.mjs +76 -103
  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 +10 -4
  18. package/dist/lib/node-esm/{chunk-CJUI6AKX.mjs → chunk-45PS7CQD.mjs} +24 -7
  19. package/dist/lib/node-esm/chunk-45PS7CQD.mjs.map +7 -0
  20. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  21. package/dist/lib/node-esm/chunk-V2SSR4MK.mjs +45 -0
  22. package/dist/lib/node-esm/chunk-V2SSR4MK.mjs.map +7 -0
  23. package/dist/lib/node-esm/cli/index.mjs +1111 -0
  24. package/dist/lib/node-esm/cli/index.mjs.map +7 -0
  25. package/dist/lib/node-esm/create-trigger-from-template-C7UPU2VL.mjs +72 -0
  26. package/dist/lib/node-esm/create-trigger-from-template-C7UPU2VL.mjs.map +7 -0
  27. package/dist/lib/node-esm/hooks/index.mjs +81 -6
  28. package/dist/lib/node-esm/hooks/index.mjs.map +4 -4
  29. package/dist/lib/node-esm/index.mjs +76 -103
  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 +10 -4
  35. package/dist/types/src/AutomationPlugin.d.ts +2 -1
  36. package/dist/types/src/AutomationPlugin.d.ts.map +1 -1
  37. package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
  38. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  39. package/dist/types/src/capabilities/compute-runtime.d.ts +12 -3
  40. package/dist/types/src/capabilities/compute-runtime.d.ts.map +1 -1
  41. package/dist/types/src/capabilities/index.d.ts +6 -5
  42. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  43. package/dist/types/src/capabilities/node.d.ts +3 -0
  44. package/dist/types/src/capabilities/node.d.ts.map +1 -0
  45. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  46. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  47. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  48. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  49. package/dist/types/src/cli/commands/index.d.ts +2 -0
  50. package/dist/types/src/cli/commands/index.d.ts.map +1 -0
  51. package/dist/types/src/cli/commands/trigger/create/index.d.ts +25 -0
  52. package/dist/types/src/cli/commands/trigger/create/index.d.ts.map +1 -0
  53. package/dist/types/src/cli/commands/trigger/create/queue.d.ts +13 -0
  54. package/dist/types/src/cli/commands/trigger/create/queue.d.ts.map +1 -0
  55. package/dist/types/src/cli/commands/trigger/create/subscription.d.ts +15 -0
  56. package/dist/types/src/cli/commands/trigger/create/subscription.d.ts.map +1 -0
  57. package/dist/types/src/cli/commands/trigger/create/timer.d.ts +13 -0
  58. package/dist/types/src/cli/commands/trigger/create/timer.d.ts.map +1 -0
  59. package/dist/types/src/cli/commands/trigger/index.d.ts +57 -0
  60. package/dist/types/src/cli/commands/trigger/index.d.ts.map +1 -0
  61. package/dist/types/src/cli/commands/trigger/list.d.ts +7 -0
  62. package/dist/types/src/cli/commands/trigger/list.d.ts.map +1 -0
  63. package/dist/types/src/cli/commands/trigger/options.d.ts +11 -0
  64. package/dist/types/src/cli/commands/trigger/options.d.ts.map +1 -0
  65. package/dist/types/src/cli/commands/trigger/remove.d.ts +8 -0
  66. package/dist/types/src/cli/commands/trigger/remove.d.ts.map +1 -0
  67. package/dist/types/src/cli/commands/trigger/update/index.d.ts +28 -0
  68. package/dist/types/src/cli/commands/trigger/update/index.d.ts.map +1 -0
  69. package/dist/types/src/cli/commands/trigger/update/queue.d.ts +12 -0
  70. package/dist/types/src/cli/commands/trigger/update/queue.d.ts.map +1 -0
  71. package/dist/types/src/cli/commands/trigger/update/subscription.d.ts +13 -0
  72. package/dist/types/src/cli/commands/trigger/update/subscription.d.ts.map +1 -0
  73. package/dist/types/src/cli/commands/trigger/update/timer.d.ts +11 -0
  74. package/dist/types/src/cli/commands/trigger/update/timer.d.ts.map +1 -0
  75. package/dist/types/src/cli/commands/trigger/util.d.ts +46 -0
  76. package/dist/types/src/cli/commands/trigger/util.d.ts.map +1 -0
  77. package/dist/types/src/cli/index.d.ts +2 -0
  78. package/dist/types/src/cli/index.d.ts.map +1 -0
  79. package/dist/types/src/cli/plugin.d.ts +3 -0
  80. package/dist/types/src/cli/plugin.d.ts.map +1 -0
  81. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +6 -7
  82. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +1 -1
  83. package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts +31 -26
  84. package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts.map +1 -1
  85. package/dist/types/src/components/FunctionsPanel/FunctionsPanel.d.ts.map +1 -1
  86. package/dist/types/src/components/FunctionsRegistry/FunctionsRegistry.d.ts +8 -0
  87. package/dist/types/src/components/FunctionsRegistry/FunctionsRegistry.d.ts.map +1 -0
  88. package/dist/types/src/components/FunctionsRegistry/index.d.ts +4 -0
  89. package/dist/types/src/components/FunctionsRegistry/index.d.ts.map +1 -0
  90. package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts +12 -9
  91. package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts.map +1 -1
  92. package/dist/types/src/components/TriggerEditor/SpecSelector.d.ts +6 -3
  93. package/dist/types/src/components/TriggerEditor/SpecSelector.d.ts.map +1 -1
  94. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +9 -8
  95. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
  96. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts +102 -28
  97. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -1
  98. package/dist/types/src/components/index.d.ts +3 -4
  99. package/dist/types/src/components/index.d.ts.map +1 -1
  100. package/dist/types/src/containers/AutomationSettings/AutomationSettings.d.ts +6 -0
  101. package/dist/types/src/containers/AutomationSettings/AutomationSettings.d.ts.map +1 -0
  102. package/dist/types/src/containers/AutomationSettings/index.d.ts +2 -0
  103. package/dist/types/src/containers/AutomationSettings/index.d.ts.map +1 -0
  104. package/dist/types/src/containers/FunctionsContainer/FunctionsContainer.d.ts +4 -0
  105. package/dist/types/src/containers/FunctionsContainer/FunctionsContainer.d.ts.map +1 -0
  106. package/dist/types/src/containers/FunctionsContainer/index.d.ts +2 -0
  107. package/dist/types/src/containers/FunctionsContainer/index.d.ts.map +1 -0
  108. package/dist/types/src/containers/TriggerSettings/TriggerSettings.d.ts.map +1 -0
  109. package/dist/types/src/containers/TriggerSettings/index.d.ts +3 -0
  110. package/dist/types/src/containers/TriggerSettings/index.d.ts.map +1 -0
  111. package/dist/types/src/containers/index.d.ts +5 -0
  112. package/dist/types/src/containers/index.d.ts.map +1 -0
  113. package/dist/types/src/hooks/index.d.ts +2 -0
  114. package/dist/types/src/hooks/index.d.ts.map +1 -1
  115. package/dist/types/src/hooks/useComputeRuntime.d.ts +8 -0
  116. package/dist/types/src/hooks/useComputeRuntime.d.ts.map +1 -0
  117. package/dist/types/src/hooks/useComputeRuntimeCallback.d.ts +5 -4
  118. package/dist/types/src/hooks/useComputeRuntimeCallback.d.ts.map +1 -1
  119. package/dist/types/src/hooks/useComputeRuntimeService.d.ts +5 -0
  120. package/dist/types/src/hooks/useComputeRuntimeService.d.ts.map +1 -0
  121. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts +6 -5
  122. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts.map +1 -1
  123. package/dist/types/src/index.d.ts +2 -5
  124. package/dist/types/src/index.d.ts.map +1 -1
  125. package/dist/types/src/meta.d.ts +2 -2
  126. package/dist/types/src/meta.d.ts.map +1 -1
  127. package/dist/types/src/operations/create-trigger-from-template.d.ts +5 -0
  128. package/dist/types/src/operations/create-trigger-from-template.d.ts.map +1 -0
  129. package/dist/types/src/operations/definitions.d.ts +19 -0
  130. package/dist/types/src/operations/definitions.d.ts.map +1 -0
  131. package/dist/types/src/operations/index.d.ts +4 -0
  132. package/dist/types/src/operations/index.d.ts.map +1 -0
  133. package/dist/types/src/testing/test-functions.d.ts +204 -3
  134. package/dist/types/src/testing/test-functions.d.ts.map +1 -1
  135. package/dist/types/src/translations.d.ts +32 -27
  136. package/dist/types/src/translations.d.ts.map +1 -1
  137. package/dist/types/src/types/capabilities.d.ts +25 -0
  138. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  139. package/dist/types/src/types/events.d.ts +5 -0
  140. package/dist/types/src/types/events.d.ts.map +1 -0
  141. package/dist/types/src/types/index.d.ts +2 -0
  142. package/dist/types/src/types/index.d.ts.map +1 -1
  143. package/dist/types/src/types/schema.d.ts +11 -3
  144. package/dist/types/src/types/schema.d.ts.map +1 -1
  145. package/dist/types/tsconfig.tsbuildinfo +1 -1
  146. package/package.json +92 -58
  147. package/src/AutomationPlugin.tsx +19 -36
  148. package/src/capabilities/app-graph-builder.ts +55 -80
  149. package/src/capabilities/compute-runtime.ts +246 -78
  150. package/src/capabilities/index.ts +9 -7
  151. package/src/capabilities/node.ts +7 -0
  152. package/src/capabilities/operation-handler.ts +16 -0
  153. package/src/capabilities/react-surface.tsx +49 -45
  154. package/src/cli/commands/index.ts +5 -0
  155. package/src/cli/commands/trigger/create/index.ts +14 -0
  156. package/src/cli/commands/trigger/create/queue.ts +87 -0
  157. package/src/cli/commands/trigger/create/subscription.ts +126 -0
  158. package/src/cli/commands/trigger/create/timer.ts +91 -0
  159. package/src/cli/commands/trigger/index.ts +16 -0
  160. package/src/cli/commands/trigger/list.ts +68 -0
  161. package/src/cli/commands/trigger/options.ts +59 -0
  162. package/src/cli/commands/trigger/remove.ts +45 -0
  163. package/src/cli/commands/trigger/update/index.ts +14 -0
  164. package/src/cli/commands/trigger/update/queue.ts +195 -0
  165. package/src/cli/commands/trigger/update/subscription.ts +279 -0
  166. package/src/cli/commands/trigger/update/timer.ts +194 -0
  167. package/src/cli/commands/trigger/util.ts +409 -0
  168. package/src/cli/index.ts +5 -0
  169. package/src/cli/plugin.ts +23 -0
  170. package/src/components/AutomationPanel/AutomationPanel.stories.tsx +8 -7
  171. package/src/components/AutomationPanel/AutomationPanel.tsx +201 -99
  172. package/src/components/FunctionsPanel/FunctionsPanel.tsx +50 -30
  173. package/src/components/FunctionsRegistry/FunctionsRegistry.tsx +114 -0
  174. package/src/components/FunctionsRegistry/index.ts +8 -0
  175. package/src/components/TriggerEditor/FunctionInputEditor.tsx +34 -33
  176. package/src/components/TriggerEditor/SpecSelector.tsx +27 -21
  177. package/src/components/TriggerEditor/TriggerEditor.stories.tsx +88 -41
  178. package/src/components/TriggerEditor/TriggerEditor.tsx +92 -50
  179. package/src/components/index.ts +1 -2
  180. package/src/containers/AutomationSettings/AutomationSettings.tsx +31 -0
  181. package/src/containers/AutomationSettings/index.ts +5 -0
  182. package/src/containers/FunctionsContainer/FunctionsContainer.tsx +34 -0
  183. package/src/containers/FunctionsContainer/index.ts +5 -0
  184. package/src/containers/TriggerSettings/TriggerSettings.tsx +48 -0
  185. package/src/containers/TriggerSettings/index.ts +6 -0
  186. package/src/containers/index.ts +9 -0
  187. package/src/hooks/index.ts +3 -0
  188. package/src/hooks/useComputeRuntime.ts +21 -0
  189. package/src/hooks/useComputeRuntimeCallback.ts +11 -9
  190. package/src/hooks/useComputeRuntimeService.ts +25 -0
  191. package/src/hooks/useTriggerRuntimeControls.ts +30 -15
  192. package/src/index.ts +2 -6
  193. package/src/meta.ts +9 -6
  194. package/src/operations/create-trigger-from-template.ts +72 -0
  195. package/src/operations/definitions.ts +28 -0
  196. package/src/operations/index.ts +9 -0
  197. package/src/testing/test-functions.ts +9 -6
  198. package/src/translations.ts +39 -33
  199. package/src/types/capabilities.ts +47 -0
  200. package/src/types/events.ts +11 -0
  201. package/src/types/index.ts +2 -0
  202. package/src/types/schema.ts +5 -5
  203. package/dist/lib/browser/AutomationPanel-3PHA5FTJ.mjs +0 -11
  204. package/dist/lib/browser/AutomationSettings-3EYSPFKB.mjs +0 -69
  205. package/dist/lib/browser/AutomationSettings-3EYSPFKB.mjs.map +0 -7
  206. package/dist/lib/browser/FunctionsContainer-HHBMPUOD.mjs +0 -36
  207. package/dist/lib/browser/FunctionsContainer-HHBMPUOD.mjs.map +0 -7
  208. package/dist/lib/browser/FunctionsPanel-NRIKAPQV.mjs +0 -10
  209. package/dist/lib/browser/app-graph-builder-DV5HMFX4.mjs +0 -81
  210. package/dist/lib/browser/app-graph-builder-DV5HMFX4.mjs.map +0 -7
  211. package/dist/lib/browser/chunk-5ARH77PV.mjs +0 -15
  212. package/dist/lib/browser/chunk-5ARH77PV.mjs.map +0 -7
  213. package/dist/lib/browser/chunk-6TUZQIEN.mjs +0 -14
  214. package/dist/lib/browser/chunk-6TUZQIEN.mjs.map +0 -7
  215. package/dist/lib/browser/chunk-DK7BLEKU.mjs +0 -14
  216. package/dist/lib/browser/chunk-DK7BLEKU.mjs.map +0 -7
  217. package/dist/lib/browser/chunk-DLLE4FKP.mjs +0 -94
  218. package/dist/lib/browser/chunk-DLLE4FKP.mjs.map +0 -7
  219. package/dist/lib/browser/chunk-MVPRI3DB.mjs +0 -53
  220. package/dist/lib/browser/chunk-MVPRI3DB.mjs.map +0 -7
  221. package/dist/lib/browser/chunk-SUKAEYF3.mjs +0 -267
  222. package/dist/lib/browser/chunk-SUKAEYF3.mjs.map +0 -7
  223. package/dist/lib/browser/chunk-VGBZKM3O.mjs +0 -38
  224. package/dist/lib/browser/chunk-VGBZKM3O.mjs.map +0 -7
  225. package/dist/lib/browser/chunk-VL3KSDVL.mjs +0 -183
  226. package/dist/lib/browser/chunk-VL3KSDVL.mjs.map +0 -7
  227. package/dist/lib/browser/chunk-WWURMV25.mjs +0 -13
  228. package/dist/lib/browser/chunk-WWURMV25.mjs.map +0 -7
  229. package/dist/lib/browser/compute-runtime-YJREH6WP.mjs +0 -160
  230. package/dist/lib/browser/compute-runtime-YJREH6WP.mjs.map +0 -7
  231. package/dist/lib/browser/intent-resolver-D2OHKQRR.mjs +0 -77
  232. package/dist/lib/browser/intent-resolver-D2OHKQRR.mjs.map +0 -7
  233. package/dist/lib/browser/react-surface-G7CG7BML.mjs +0 -63
  234. package/dist/lib/browser/react-surface-G7CG7BML.mjs.map +0 -7
  235. package/dist/lib/node-esm/AutomationPanel-EETYIR35.mjs +0 -12
  236. package/dist/lib/node-esm/AutomationPanel-EETYIR35.mjs.map +0 -7
  237. package/dist/lib/node-esm/AutomationSettings-WKSMWITV.mjs +0 -70
  238. package/dist/lib/node-esm/AutomationSettings-WKSMWITV.mjs.map +0 -7
  239. package/dist/lib/node-esm/FunctionsContainer-ZKVOBUHV.mjs +0 -37
  240. package/dist/lib/node-esm/FunctionsContainer-ZKVOBUHV.mjs.map +0 -7
  241. package/dist/lib/node-esm/FunctionsPanel-SAMRTELO.mjs +0 -11
  242. package/dist/lib/node-esm/FunctionsPanel-SAMRTELO.mjs.map +0 -7
  243. package/dist/lib/node-esm/app-graph-builder-TR2WXPX2.mjs +0 -82
  244. package/dist/lib/node-esm/app-graph-builder-TR2WXPX2.mjs.map +0 -7
  245. package/dist/lib/node-esm/chunk-2EWXIFEK.mjs +0 -16
  246. package/dist/lib/node-esm/chunk-2EWXIFEK.mjs.map +0 -7
  247. package/dist/lib/node-esm/chunk-5MQJPJR2.mjs +0 -15
  248. package/dist/lib/node-esm/chunk-5MQJPJR2.mjs.map +0 -7
  249. package/dist/lib/node-esm/chunk-AKHETVIQ.mjs +0 -184
  250. package/dist/lib/node-esm/chunk-AKHETVIQ.mjs.map +0 -7
  251. package/dist/lib/node-esm/chunk-B7N3H45O.mjs +0 -16
  252. package/dist/lib/node-esm/chunk-B7N3H45O.mjs.map +0 -7
  253. package/dist/lib/node-esm/chunk-CJUI6AKX.mjs.map +0 -7
  254. package/dist/lib/node-esm/chunk-J3XEBEIE.mjs +0 -268
  255. package/dist/lib/node-esm/chunk-J3XEBEIE.mjs.map +0 -7
  256. package/dist/lib/node-esm/chunk-QCA543ZR.mjs +0 -54
  257. package/dist/lib/node-esm/chunk-QCA543ZR.mjs.map +0 -7
  258. package/dist/lib/node-esm/chunk-WHCSOUNN.mjs +0 -16
  259. package/dist/lib/node-esm/chunk-WHCSOUNN.mjs.map +0 -7
  260. package/dist/lib/node-esm/chunk-YQXW3JXD.mjs +0 -95
  261. package/dist/lib/node-esm/chunk-YQXW3JXD.mjs.map +0 -7
  262. package/dist/lib/node-esm/compute-runtime-CMEPAYND.mjs +0 -161
  263. package/dist/lib/node-esm/compute-runtime-CMEPAYND.mjs.map +0 -7
  264. package/dist/lib/node-esm/intent-resolver-2LGBVXT5.mjs +0 -78
  265. package/dist/lib/node-esm/intent-resolver-2LGBVXT5.mjs.map +0 -7
  266. package/dist/lib/node-esm/react-surface-OMZSBDHS.mjs +0 -64
  267. package/dist/lib/node-esm/react-surface-OMZSBDHS.mjs.map +0 -7
  268. package/dist/types/src/capabilities/capabilities.d.ts +0 -19
  269. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  270. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  271. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  272. package/dist/types/src/components/AutomationSettings.d.ts +0 -5
  273. package/dist/types/src/components/AutomationSettings.d.ts.map +0 -1
  274. package/dist/types/src/components/FunctionsContainer.d.ts +0 -7
  275. package/dist/types/src/components/FunctionsContainer.d.ts.map +0 -1
  276. package/dist/types/src/components/TriggerSettings.d.ts.map +0 -1
  277. package/dist/types/src/events.d.ts +0 -4
  278. package/dist/types/src/events.d.ts.map +0 -1
  279. package/src/capabilities/capabilities.ts +0 -48
  280. package/src/capabilities/intent-resolver.ts +0 -72
  281. package/src/components/AutomationSettings.tsx +0 -30
  282. package/src/components/FunctionsContainer.tsx +0 -29
  283. package/src/components/TriggerSettings.tsx +0 -25
  284. package/src/events.ts +0 -11
  285. /package/dist/lib/browser/{AutomationPanel-3PHA5FTJ.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
  286. /package/dist/lib/{browser/FunctionsPanel-NRIKAPQV.mjs.map → node-esm/chunk-HSLMI22Q.mjs.map} +0 -0
  287. /package/dist/types/src/{components → containers/TriggerSettings}/TriggerSettings.d.ts +0 -0
@@ -3,60 +3,73 @@
3
3
  //
4
4
 
5
5
  import * as Array from 'effect/Array';
6
- import * as Function from 'effect/Function';
6
+ import * as EFn from 'effect/Function';
7
7
  import * as Match from 'effect/Match';
8
8
  import * as Schema from 'effect/Schema';
9
- import React, { useMemo, useState } from 'react';
9
+ import React, { useCallback, useMemo, useState } from 'react';
10
10
 
11
+ import { useTypeOptions } from '@dxos/app-toolkit/ui';
12
+ import { Context } from '@dxos/context';
11
13
  import { Filter, Obj, Tag } from '@dxos/echo';
12
- import { FunctionTrigger, FunctionType, ScriptType } from '@dxos/functions';
13
- import { useTypeOptions } from '@dxos/plugin-space';
14
+ import { Script, Trigger } from '@dxos/functions';
15
+ import { KEY_QUEUE_CURSOR } from '@dxos/functions-runtime';
16
+ import { FunctionsServiceClient } from '@dxos/functions-runtime/edge';
17
+ import { Operation } from '@dxos/operation';
14
18
  import { type Client, useClient } from '@dxos/react-client';
15
- import { type Space, getSpace, useQuery } from '@dxos/react-client/echo';
16
- import { Clipboard, IconButton, Input, Separator, type ThemedClassName, useTranslation } from '@dxos/react-ui';
17
- import { ControlItem, controlItemClasses } from '@dxos/react-ui-form';
19
+ import { type Space, useObject, useQuery } from '@dxos/react-client/echo';
20
+ import { Clipboard, IconButton, type IconButtonProps, Input, Separator, useTranslation } from '@dxos/react-ui';
21
+ import { Settings } from '@dxos/react-ui-form';
18
22
  import { List } from '@dxos/react-ui-list';
19
- import { ghostHover, mx } from '@dxos/react-ui-theme';
20
- import { DataType } from '@dxos/schema';
23
+ import { Pipeline } from '@dxos/types';
24
+ import { ghostHover, mx } from '@dxos/ui-theme';
25
+ import { isNonNullable } from '@dxos/util';
26
+
27
+ import { meta } from '#meta';
21
28
 
22
- import { meta } from '../../meta';
23
29
  import { TriggerEditor, type TriggerEditorProps } from '../TriggerEditor';
24
30
 
25
- const grid = 'grid grid-cols-[40px_1fr_32px] min-bs-[2.5rem]';
31
+ const grid = 'grid grid-cols-[40px_1fr_32px_32px] min-h-[2.5rem]';
26
32
 
27
- export type AutomationPanelProps = ThemedClassName<{
33
+ export type AutomationPanelProps = {
28
34
  space: Space;
29
- object?: Obj.Any;
30
- initialTrigger?: FunctionTrigger;
35
+ object?: Obj.Unknown;
36
+ initialTrigger?: Trigger.Trigger;
31
37
  onDone?: () => void;
32
- }>;
38
+ };
33
39
 
34
40
  // TODO(burdon): Factor out common layout with ViewEditor.
35
- export const AutomationPanel = ({ classNames, space, object, initialTrigger, onDone }: AutomationPanelProps) => {
41
+ export const AutomationPanel = ({ space, object, initialTrigger, onDone }: AutomationPanelProps) => {
36
42
  const { t } = useTranslation(meta.id);
37
43
  const client = useClient();
38
- const functions = useQuery(space, Filter.type(FunctionType));
39
- const triggers = useQuery(space, Filter.type(FunctionTrigger));
44
+ const functionsServiceClient = useMemo(() => FunctionsServiceClient.fromClient(client), [client]);
45
+ const functions = useQuery(space.db, Filter.type(Operation.PersistentOperation));
46
+ const triggers = useQuery(space.db, Filter.type(Trigger.Trigger));
40
47
  const filteredTriggers = useMemo(() => {
41
48
  return object ? triggers.filter(triggerMatch(object)) : triggers;
42
49
  }, [object, triggers]);
43
- const tags = useQuery(space, Filter.type(Tag.Tag));
44
- const types = useTypeOptions({ space, annotation: ['dynamic', 'limited-static', 'object-form'] });
50
+ const tags = useQuery(space.db, Filter.type(Tag.Tag));
51
+ const types = useTypeOptions({
52
+ space,
53
+ annotation: {
54
+ location: ['database', 'runtime'],
55
+ kind: ['user'],
56
+ },
57
+ });
45
58
 
46
- const [trigger, setTrigger] = useState<FunctionTrigger | undefined>(initialTrigger);
47
- const [selected, setSelected] = useState<FunctionTrigger>();
59
+ const [trigger, setTrigger] = useState<Trigger.Trigger | undefined>(initialTrigger);
60
+ const [selected, setSelected] = useState<Trigger.Trigger>();
48
61
 
49
- const handleSelect = (trigger: FunctionTrigger) => {
62
+ const handleSelect = (trigger: Trigger.Trigger) => {
50
63
  setTrigger(trigger);
51
64
  setSelected(trigger);
52
65
  };
53
66
 
54
67
  const handleAdd = () => {
55
- setTrigger(Obj.make(FunctionTrigger, {}));
68
+ setTrigger(Trigger.make({}));
56
69
  setSelected(undefined);
57
70
  };
58
71
 
59
- const handleDelete = (trigger: FunctionTrigger) => {
72
+ const handleDelete = (trigger: Trigger.Trigger) => {
60
73
  space.db.remove(trigger);
61
74
  setTrigger(undefined);
62
75
  setSelected(undefined);
@@ -64,9 +77,11 @@ export const AutomationPanel = ({ classNames, space, object, initialTrigger, onD
64
77
 
65
78
  const handleSave: TriggerEditorProps['onSave'] = (trigger) => {
66
79
  if (selected) {
67
- Object.assign(selected, trigger);
80
+ Obj.change(selected, (selected) => {
81
+ Object.assign(selected, trigger);
82
+ });
68
83
  } else {
69
- space.db.add(Obj.make(FunctionTrigger, trigger));
84
+ space.db.add(Trigger.make(trigger));
70
85
  }
71
86
 
72
87
  setTrigger(undefined);
@@ -79,11 +94,22 @@ export const AutomationPanel = ({ classNames, space, object, initialTrigger, onD
79
94
  onDone?.();
80
95
  };
81
96
 
97
+ const handleForceRunTrigger = async (trigger: Trigger.Trigger) => {
98
+ await functionsServiceClient.forceRunCronTrigger(Context.default(), space.id, trigger.id);
99
+ };
100
+
101
+ const handleResetCursor = async (trigger: Trigger.Trigger) => {
102
+ Obj.change(trigger, (trigger) => {
103
+ Obj.deleteKeys(trigger, KEY_QUEUE_CURSOR);
104
+ });
105
+ await space.db.flush({ indexes: true });
106
+ };
107
+
82
108
  if (trigger) {
83
109
  return (
84
- <ControlItem title={t('trigger editor title')}>
110
+ <Settings.Item title={t('trigger-editor.title')} description={t('trigger-editor.description')}>
85
111
  <TriggerEditor
86
- space={space}
112
+ db={space.db}
87
113
  trigger={trigger}
88
114
  readonlySpec={Boolean(object)}
89
115
  tags={tags}
@@ -91,87 +117,163 @@ export const AutomationPanel = ({ classNames, space, object, initialTrigger, onD
91
117
  onSave={handleSave}
92
118
  onCancel={handleCancel}
93
119
  />
94
- </ControlItem>
120
+ </Settings.Item>
95
121
  );
96
122
  }
97
123
 
98
124
  return (
99
- <div className={mx(controlItemClasses, classNames)}>
100
- {filteredTriggers.length > 0 && (
101
- <List.Root<FunctionTrigger>
102
- items={filteredTriggers}
103
- isItem={Schema.is(FunctionTrigger)}
104
- getId={(field) => field.id}
105
- >
106
- {({ items: filteredTriggers }) => (
107
- <div role='list' className='flex flex-col w-full'>
108
- {filteredTriggers?.map((trigger) => {
109
- const copyAction = getCopyAction(client, trigger);
110
- return (
111
- <List.Item<FunctionTrigger>
125
+ <Settings.Panel>
126
+ <Clipboard.Provider>
127
+ {filteredTriggers.length > 0 && (
128
+ <List.Root<Trigger.Trigger>
129
+ items={filteredTriggers}
130
+ isItem={Schema.is(Trigger.Trigger)}
131
+ getId={(field) => field.id}
132
+ >
133
+ {({ items: filteredTriggers }) => (
134
+ <div role='list' className='flex flex-col w-full'>
135
+ {filteredTriggers?.map((trigger) => (
136
+ <TriggerListItem
112
137
  key={trigger.id}
113
- item={trigger}
114
- classNames={mx(grid, ghostHover, 'items-center', 'px-2')}
115
- >
116
- <Input.Root>
117
- <Input.Switch
118
- checked={trigger.enabled}
119
- onCheckedChange={(checked) => (trigger.enabled = checked)}
120
- />
121
- </Input.Root>
122
-
123
- <div className={'flex'}>
124
- <List.ItemTitle
125
- classNames='px-1 cursor-pointer w-0 shrink truncate'
126
- onClick={() => handleSelect(trigger)}
127
- >
128
- {getFunctionName(functions, trigger) ?? '∅'}
129
- </List.ItemTitle>
130
-
131
- {/* TODO: a better way to expose copy action */}
132
- {copyAction && (
133
- <Clipboard.IconButton
134
- label={t(copyAction.translationKey)}
135
- value={copyAction.contentProvider()}
136
- />
137
- )}
138
- </div>
139
-
140
- <List.ItemDeleteButton onClick={() => handleDelete(trigger)} />
141
- </List.Item>
142
- );
143
- })}
144
- </div>
145
- )}
146
- </List.Root>
147
- )}
148
- {filteredTriggers.length > 0 && <Separator classNames='mlb-4' />}
149
- <IconButton icon='ph--plus--regular' label={t('new trigger label')} onClick={handleAdd} />
150
- </div>
138
+ trigger={trigger}
139
+ functions={functions}
140
+ onSelect={handleSelect}
141
+ onDelete={handleDelete}
142
+ onResetCursor={handleResetCursor}
143
+ onForceRun={handleForceRunTrigger}
144
+ />
145
+ ))}
146
+ </div>
147
+ )}
148
+ </List.Root>
149
+ )}
150
+
151
+ {filteredTriggers.length > 0 && <Separator classNames='my-4' />}
152
+ <IconButton icon='ph--plus--regular' label={t('new-trigger.label')} onClick={handleAdd} />
153
+ </Clipboard.Provider>
154
+ </Settings.Panel>
155
+ );
156
+ };
157
+
158
+ const TriggerListItem = ({
159
+ trigger,
160
+ functions,
161
+ onSelect,
162
+ onDelete,
163
+ onResetCursor,
164
+ onForceRun,
165
+ }: {
166
+ trigger: Trigger.Trigger;
167
+ functions: Operation.PersistentOperation[];
168
+ onSelect?: (trigger: Trigger.Trigger) => void;
169
+ onDelete?: (trigger: Trigger.Trigger) => void;
170
+ onResetCursor?: (trigger: Trigger.Trigger) => void;
171
+ onForceRun?: (trigger: Trigger.Trigger) => void;
172
+ }) => {
173
+ const client = useClient();
174
+ const copyAction = getCopyAction(client, trigger);
175
+ const { t } = useTranslation(meta.id);
176
+ const cursor = Obj.getKeys(trigger, KEY_QUEUE_CURSOR).at(0)?.id;
177
+ const [snapshot, updateTrigger] = useObject(trigger);
178
+
179
+ const enabled = snapshot.enabled ?? false;
180
+ const onEnabledChange = (checked: boolean) => {
181
+ updateTrigger((trigger) => {
182
+ trigger.enabled = checked;
183
+ });
184
+ };
185
+
186
+ const handleSelect = useCallback(() => {
187
+ onSelect?.(trigger);
188
+ }, [onSelect, trigger]);
189
+
190
+ const handleDelete = useCallback(() => {
191
+ onDelete?.(trigger);
192
+ }, [onDelete, trigger]);
193
+
194
+ const handleResetCursor = useCallback(() => {
195
+ onResetCursor?.(trigger);
196
+ }, [onResetCursor, trigger]);
197
+
198
+ const handleForceRun = useCallback(() => {
199
+ onForceRun?.(trigger);
200
+ }, [onForceRun, trigger]);
201
+
202
+ const actionProps = useMemo<IconButtonProps | undefined>(() => {
203
+ if (trigger.spec?.kind === 'timer' && onForceRun) {
204
+ return {
205
+ disabled: !enabled || trigger.spec?.kind !== 'timer',
206
+ icon: 'ph--play--regular',
207
+ label: 'Force run',
208
+ onClick: handleForceRun,
209
+ };
210
+ }
211
+
212
+ if (trigger.spec?.kind === 'queue' && onResetCursor) {
213
+ return {
214
+ disabled: !cursor,
215
+ icon: 'ph--arrow-clockwise--regular',
216
+ label: 'Reset cursor',
217
+ onClick: handleResetCursor,
218
+ };
219
+ }
220
+ }, [enabled, trigger.spec?.kind, handleForceRun]);
221
+
222
+ return (
223
+ <List.Item<Obj.Snapshot<Trigger.Trigger>>
224
+ key={trigger.id}
225
+ item={snapshot}
226
+ classNames={mx(grid, ghostHover, 'items-center', 'px-2')}
227
+ >
228
+ <Input.Root>
229
+ <Input.Switch checked={enabled} onCheckedChange={onEnabledChange} />
230
+ </Input.Root>
231
+
232
+ <div className={'flex'}>
233
+ <List.ItemTitle classNames='px-1 cursor-pointer w-0 shrink truncate' onClick={handleSelect}>
234
+ {getFunctionName(functions, trigger) ?? '∅'}
235
+ {cursor && <div className='text-xs text-description truncate ml-4'>Position: {cursor}</div>}
236
+ </List.ItemTitle>
237
+
238
+ {copyAction && (
239
+ <Clipboard.IconButton label={t(copyAction.translationKey)} value={copyAction.contentProvider()} />
240
+ )}
241
+ </div>
242
+
243
+ {actionProps ? <List.ItemIconButton {...actionProps} autoHide={false} /> : <div />}
244
+
245
+ {onDelete && <List.ItemDeleteButton onClick={handleDelete} />}
246
+ </List.Item>
151
247
  );
152
248
  };
153
249
 
154
- const getCopyAction = (client: Client, trigger: FunctionTrigger | undefined) => {
250
+ const getCopyAction = (client: Client, trigger: Trigger.Trigger | undefined) => {
155
251
  if (trigger?.spec?.kind === 'email') {
156
- return { translationKey: 'trigger copy email', contentProvider: () => `${getSpace(trigger)!.id}@dxos.network` };
252
+ return {
253
+ translationKey: 'trigger copy email' as const,
254
+ contentProvider: () => `${Obj.getDatabase(trigger)!.spaceId}@dxos.network`,
255
+ };
157
256
  }
158
257
 
159
258
  if (trigger?.spec?.kind === 'webhook') {
160
- return { translationKey: 'trigger copy url', contentProvider: () => getWebhookUrl(client, trigger) };
259
+ return {
260
+ translationKey: 'trigger copy url' as const,
261
+ contentProvider: () => getWebhookUrl(client, trigger!),
262
+ };
161
263
  }
162
264
 
163
265
  return undefined;
164
266
  };
165
267
 
166
- const getWebhookUrl = (client: Client, trigger: FunctionTrigger) => {
167
- const spaceId = getSpace(trigger)!.id;
268
+ const getWebhookUrl = (client: Client, trigger: Trigger.Trigger) => {
269
+ const spaceId = Obj.getDatabase(trigger)!.spaceId;
168
270
  const edgeUrl = new URL(client.config.values.runtime!.services!.edge!.url!);
169
271
  const isSecure = edgeUrl.protocol.startsWith('https') || edgeUrl.protocol.startsWith('wss');
170
272
  edgeUrl.protocol = isSecure ? 'https' : 'http';
171
273
  return new URL(`/webhook/${spaceId}:${trigger.id}`, edgeUrl).toString();
172
274
  };
173
275
 
174
- const getFunctionName = (functions: FunctionType[], trigger: FunctionTrigger) => {
276
+ const getFunctionName = (functions: Operation.PersistentOperation[], trigger: Trigger.Trigger) => {
175
277
  // TODO(wittjosiah): Truncation should be done in the UI.
176
278
  // Warning that the List component is currently a can of worms.
177
279
  const shortId = trigger.function && `${trigger.function.dxn.toString().slice(0, 16)}…`;
@@ -179,25 +281,25 @@ const getFunctionName = (functions: FunctionType[], trigger: FunctionTrigger) =>
179
281
  return functionObject?.name ?? shortId;
180
282
  };
181
283
 
182
- const scriptMatch = (script: ScriptType) => (trigger: FunctionTrigger) => {
284
+ const scriptMatch = (script: Script.Script) => (trigger: Trigger.Trigger) => {
183
285
  const fn = trigger.function?.target;
184
- if (!Obj.instanceOf(FunctionType, fn)) {
286
+ if (!Obj.instanceOf(Operation.PersistentOperation, fn)) {
185
287
  return false;
186
288
  }
187
289
 
188
290
  return fn.source?.target === script;
189
291
  };
190
292
 
191
- const projectMatch = (project: DataType.Project) => {
192
- const viewQueries = Function.pipe(
193
- project.collections,
194
- Array.map((collection) => collection.target),
195
- Array.filter(Schema.is(DataType.View)),
293
+ const projectMatch = (project: Pipeline.Pipeline) => {
294
+ const viewQueries = EFn.pipe(
295
+ project.columns,
296
+ Array.map((column) => column.view.target),
297
+ Array.filter(isNonNullable),
196
298
  Array.map((view) => Obj.getSnapshot(view).query.ast),
197
299
  Array.map((ast) => JSON.stringify(ast)),
198
300
  );
199
301
 
200
- return (trigger: FunctionTrigger) => {
302
+ return (trigger: Trigger.Trigger) => {
201
303
  const spec = Obj.getSnapshot(trigger).spec;
202
304
  if (spec?.kind !== 'subscription') {
203
305
  return false;
@@ -208,14 +310,14 @@ const projectMatch = (project: DataType.Project) => {
208
310
  };
209
311
  };
210
312
 
211
- const triggerMatch = Match.type<Obj.Any>().pipe(
212
- Match.withReturnType<(trigger: FunctionTrigger) => boolean>(),
313
+ const triggerMatch = Match.type<Obj.Unknown>().pipe(
314
+ Match.withReturnType<(trigger: Trigger.Trigger) => boolean>(),
213
315
  Match.when(
214
- (obj) => Obj.instanceOf(ScriptType, obj),
316
+ (obj) => Obj.instanceOf(Script.Script, obj),
215
317
  (obj) => scriptMatch(obj),
216
318
  ),
217
319
  Match.when(
218
- (obj) => Obj.instanceOf(DataType.Project, obj),
320
+ (obj) => Obj.instanceOf(Pipeline.Pipeline, obj),
219
321
  (obj) => projectMatch(obj),
220
322
  ),
221
323
  Match.orElse((_obj) => () => true),
@@ -5,17 +5,18 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import React, { useCallback, useMemo } from 'react';
7
7
 
8
- import { LayoutAction, createIntent, useIntentDispatcher } from '@dxos/app-framework';
9
- import { FunctionType, ScriptType } from '@dxos/functions';
10
- import { Filter, type Space, fullyQualifiedId, useQuery } from '@dxos/react-client/echo';
11
- import { Button, useTranslation } from '@dxos/react-ui';
12
- import { controlItemClasses } from '@dxos/react-ui-form';
8
+ import { useOperationInvoker } from '@dxos/app-framework/ui';
9
+ import { LayoutOperation, getObjectPathFromObject } from '@dxos/app-toolkit';
10
+ import { Script } from '@dxos/functions';
11
+ import { Operation } from '@dxos/operation';
12
+ import { SpaceOperation } from '@dxos/plugin-space/operations';
13
+ import { Filter, type Space, useQuery } from '@dxos/react-client/echo';
14
+ import { IconButton, useTranslation } from '@dxos/react-ui';
15
+ import { Settings } from '@dxos/react-ui-form';
13
16
  import { List } from '@dxos/react-ui-list';
14
- import { ghostHover, mx } from '@dxos/react-ui-theme';
17
+ import { ghostHover, mx } from '@dxos/ui-theme';
15
18
 
16
- import { meta } from '../../meta';
17
-
18
- const grid = 'grid grid-cols-[1fr_auto] min-bs-[2.5rem]';
19
+ import { meta } from '#meta';
19
20
 
20
21
  export type FunctionsPanelProps = {
21
22
  space: Space;
@@ -23,9 +24,9 @@ export type FunctionsPanelProps = {
23
24
 
24
25
  export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
25
26
  const { t } = useTranslation(meta.id);
26
- const functions = useQuery(space, Filter.type(FunctionType));
27
- const scripts = useQuery(space, Filter.type(ScriptType));
28
- const { dispatchPromise: dispatch } = useIntentDispatcher();
27
+ const functions = useQuery(space.db, Filter.type(Operation.PersistentOperation));
28
+ const scripts = useQuery(space.db, Filter.type(Script.Script));
29
+ const { invokePromise } = useOperationInvoker();
29
30
 
30
31
  const functionToScriptMap = useMemo(
31
32
  () =>
@@ -40,13 +41,13 @@ export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
40
41
  }
41
42
  return map;
42
43
  },
43
- {} as Record<string, ScriptType>,
44
+ {} as Record<string, Script.Script>,
44
45
  ),
45
46
  [functions, scripts],
46
47
  );
47
48
 
48
49
  const getScriptName = useCallback(
49
- (func: FunctionType) => {
50
+ (func: Operation.PersistentOperation) => {
50
51
  const script = functionToScriptMap[func.id];
51
52
  return script?.name;
52
53
  },
@@ -54,44 +55,63 @@ export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
54
55
  );
55
56
 
56
57
  const handleGoToScript = useCallback(
57
- (func: FunctionType) => {
58
+ (func: Operation.PersistentOperation) => {
58
59
  const script = functionToScriptMap[func.id];
59
60
  if (script) {
60
- void dispatch(createIntent(LayoutAction.Open, { part: 'main', subject: [fullyQualifiedId(script)] }));
61
+ void invokePromise(LayoutOperation.Open, { subject: [getObjectPathFromObject(script)] });
61
62
  }
62
63
  },
63
- [functionToScriptMap, dispatch],
64
+ [functionToScriptMap, invokePromise],
65
+ );
66
+
67
+ const handleDelete = useCallback(
68
+ (func: Operation.PersistentOperation) => invokePromise(SpaceOperation.RemoveObjects, { objects: [func] }),
69
+ [invokePromise],
64
70
  );
65
71
 
66
72
  return (
67
- <div role='none' className={mx(controlItemClasses)}>
73
+ <Settings.Panel>
68
74
  {functions.length > 0 && (
69
- <List.Root<FunctionType> items={functions} isItem={Schema.is(FunctionType)} getId={(func) => func.id}>
75
+ <List.Root<Operation.PersistentOperation>
76
+ items={functions}
77
+ isItem={Schema.is(Operation.PersistentOperation)}
78
+ getId={(func) => func.id}
79
+ >
70
80
  {({ items }) => (
71
81
  <div role='list' className='flex flex-col w-full'>
72
82
  {items?.map((func) => (
73
- <List.Item<FunctionType>
83
+ <List.Item<Operation.PersistentOperation>
74
84
  key={func.id}
75
85
  item={func}
76
- classNames={mx(grid, ghostHover, 'items-center', 'pli-2', 'min-bs-[3rem]')}
86
+ classNames={mx(
87
+ 'grid grid-cols-[1fr_min-content_auto] min-h-[2.5rem] min-h-[3rem] px-2 items-center',
88
+ ghostHover,
89
+ )}
77
90
  >
78
91
  <div className='flex flex-col truncate'>
79
92
  <List.ItemTitle classNames='truncate'>{func.name}</List.ItemTitle>
80
- {getScriptName(func) && (
81
- <div className='text-xs text-description truncate'>{getScriptName(func)}</div>
82
- )}
93
+ {getScriptName(func) && <p className='text-xs text-description truncate'>{getScriptName(func)}</p>}
83
94
  </div>
84
- {functionToScriptMap[func.id] && (
85
- <Button onClick={() => handleGoToScript(func)}>{t('go to function source button label')}</Button>
86
- )}
95
+ {(functionToScriptMap[func.id] && (
96
+ <IconButton
97
+ icon='ph--arrow-square-out--regular'
98
+ iconOnly
99
+ label={t('show-source-button.label')}
100
+ onClick={() => handleGoToScript(func)}
101
+ />
102
+ )) || <div />}
103
+ <IconButton
104
+ icon='ph--trash--regular'
105
+ iconOnly
106
+ label={t('delete-function-button.label')}
107
+ onClick={() => handleDelete(func)}
108
+ />
87
109
  </List.Item>
88
110
  ))}
89
111
  </div>
90
112
  )}
91
113
  </List.Root>
92
114
  )}
93
-
94
- {functions.length === 0 && <div className='text-center plb-4 text-gray-500'>{t('no functions found')}</div>}
95
- </div>
115
+ </Settings.Panel>
96
116
  );
97
117
  };
@@ -0,0 +1,114 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import { useState } from 'react';
7
+ import React, { useCallback } from 'react';
8
+
9
+ import { Context } from '@dxos/context';
10
+ import { getDeployedFunctions } from '@dxos/functions-runtime/edge';
11
+ import * as OperationModule from '@dxos/operation';
12
+ import { useClient } from '@dxos/react-client';
13
+ import { Filter, Query, type Space, useQuery } from '@dxos/react-client/echo';
14
+ import { IconButton, useAsyncEffect, useTranslation } from '@dxos/react-ui';
15
+ import { Settings } from '@dxos/react-ui-form';
16
+ import { List } from '@dxos/react-ui-list';
17
+ import { ghostHover, mx } from '@dxos/ui-theme';
18
+
19
+ import { meta } from '#meta';
20
+
21
+ const grid = 'grid grid-cols-[1fr_1fr_auto] min-h-[2.5rem]';
22
+
23
+ type FunctionsRegistryProps = {
24
+ space: Space;
25
+ };
26
+
27
+ export const FunctionsRegistry = ({ space }: FunctionsRegistryProps) => {
28
+ const client = useClient();
29
+ const [loading, setLoading] = useState(true);
30
+ const [functions, setFunctions] = useState<OperationModule.Operation.PersistentOperation[]>([]);
31
+ const { t } = useTranslation(meta.id);
32
+
33
+ const dbFunctions = useQuery(space.db, Filter.type(OperationModule.Operation.PersistentOperation));
34
+
35
+ const state = (func: OperationModule.Operation.PersistentOperation) => {
36
+ const dbFunction = dbFunctions.find((f) => f.key === func.key);
37
+ if (!dbFunction) {
38
+ return 'import';
39
+ }
40
+ if (dbFunction.version === func.version && dbFunction.updated === func.updated) {
41
+ return 'none';
42
+ }
43
+ return 'update';
44
+ };
45
+
46
+ useAsyncEffect(async () => {
47
+ setLoading(true);
48
+ const functions = await getDeployedFunctions(Context.default(), client, true);
49
+ setFunctions(functions);
50
+ setLoading(false);
51
+ }, []);
52
+
53
+ const hanleImportOrUpdate = useCallback(
54
+ async (func: OperationModule.Operation.PersistentOperation) => {
55
+ const functions = await space.db
56
+ .query(Query.type(OperationModule.Operation.PersistentOperation, { key: func.key }))
57
+ .run();
58
+ const [existingFunc] = functions;
59
+ if (!existingFunc) {
60
+ space.db.add(func);
61
+ return;
62
+ }
63
+ OperationModule.Operation.setFrom(existingFunc, func);
64
+ },
65
+ [space],
66
+ );
67
+
68
+ return (
69
+ <Settings.Panel>
70
+ {functions.length > 0 && (
71
+ <List.Root<OperationModule.Operation.PersistentOperation>
72
+ items={functions}
73
+ isItem={Schema.is(OperationModule.Operation.PersistentOperation)}
74
+ getId={(func) => func.id}
75
+ >
76
+ {({ items }) => (
77
+ <div role='list' className='flex flex-col w-full'>
78
+ {items?.map((func) => (
79
+ <List.Item<OperationModule.Operation.PersistentOperation>
80
+ key={func.id}
81
+ item={func}
82
+ classNames={mx(grid, ghostHover, 'items-center', 'px-2', 'min-h-[3rem]')}
83
+ >
84
+ <div className='flex flex-col truncate'>
85
+ <List.ItemTitle classNames='truncate'>{func.name}</List.ItemTitle>
86
+ <div className='text-xs text-description truncate'>{func.key}</div>
87
+ </div>
88
+ <div className='flex flex-col truncate'>
89
+ <div className='text-xs text-description truncate'>{func.version}</div>
90
+ <div className='text-xs text-description truncate'>
91
+ {func.updated ? `Uploaded ${new Date(func.updated).toLocaleString()}` : ''}
92
+ </div>
93
+ </div>
94
+
95
+ <IconButton
96
+ iconOnly
97
+ icon={state(func) === 'update' ? 'ph--arrows-clockwise--regular' : 'ph--download--regular'}
98
+ label={
99
+ state(func) === 'update' ? t('update-function-button.label') : t('import-function-button.label')
100
+ }
101
+ disabled={state(func) === 'none'}
102
+ onClick={() => hanleImportOrUpdate(func)}
103
+ />
104
+ </List.Item>
105
+ ))}
106
+ </div>
107
+ )}
108
+ </List.Root>
109
+ )}
110
+
111
+ {loading && <div className='text-center py-4 text-gray-500'>{t('loading-functions.message')}</div>}
112
+ </Settings.Panel>
113
+ );
114
+ };
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { FunctionsRegistry } from './FunctionsRegistry';
6
+
7
+ export { FunctionsRegistry };
8
+ export default FunctionsRegistry;