@dxos/plugin-routine 0.10.0 → 0.11.0

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 (320) hide show
  1. package/PLUGIN.mdl +18 -13
  2. package/dist/lib/RoutinePlugin.mjs +2 -0
  3. package/dist/lib/RoutinePlugin.node.mjs +894 -0
  4. package/dist/lib/RoutinePlugin.node.mjs.map +1 -0
  5. package/dist/lib/RoutinePlugin.workerd.mjs +20 -0
  6. package/dist/lib/RoutinePlugin.workerd.mjs.map +1 -0
  7. package/dist/lib/capabilities/node.mjs +12 -0
  8. package/dist/lib/capabilities/node.mjs.map +1 -0
  9. package/dist/lib/capabilities.mjs +14 -0
  10. package/dist/lib/capabilities.mjs.map +1 -0
  11. package/dist/lib/chunk-RoutineArticle.mjs +79 -0
  12. package/dist/lib/chunk-RoutineArticle.mjs.map +1 -0
  13. package/dist/lib/chunk-RoutineCompanion.mjs +192 -0
  14. package/dist/lib/chunk-RoutineCompanion.mjs.map +1 -0
  15. package/dist/lib/chunk-RoutinePlugin.mjs +38 -0
  16. package/dist/lib/chunk-RoutinePlugin.mjs.map +1 -0
  17. package/dist/lib/chunk-RoutineSettings.mjs +50 -0
  18. package/dist/lib/chunk-RoutineSettings.mjs.map +1 -0
  19. package/dist/lib/chunk-RoutineTraceCompanion.mjs +208 -0
  20. package/dist/lib/chunk-RoutineTraceCompanion.mjs.map +1 -0
  21. package/dist/lib/chunk-SkillArticle.mjs +28 -0
  22. package/dist/lib/chunk-SkillArticle.mjs.map +1 -0
  23. package/dist/lib/chunk-app-graph-builder.mjs +71 -0
  24. package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
  25. package/dist/lib/chunk-create-object.mjs +23 -0
  26. package/dist/lib/chunk-create-object.mjs.map +1 -0
  27. package/dist/lib/chunk-create-routine.mjs +34 -0
  28. package/dist/lib/chunk-create-routine.mjs.map +1 -0
  29. package/dist/lib/chunk-create-trigger-from-template.mjs +48 -0
  30. package/dist/lib/chunk-create-trigger-from-template.mjs.map +1 -0
  31. package/dist/lib/chunk-layer-specs.mjs +179 -0
  32. package/dist/lib/chunk-layer-specs.mjs.map +1 -0
  33. package/dist/lib/{neutral/chunk-HLO4LYXT.mjs → chunk-meta.mjs} +19 -27
  34. package/dist/lib/chunk-meta.mjs.map +1 -0
  35. package/dist/lib/chunk-operation-handler.mjs +11 -0
  36. package/dist/lib/chunk-operation-handler.mjs.map +1 -0
  37. package/dist/lib/chunk-paths.mjs +11 -0
  38. package/dist/lib/chunk-paths.mjs.map +1 -0
  39. package/dist/lib/chunk-react-surface.mjs +64 -0
  40. package/dist/lib/chunk-react-surface.mjs.map +1 -0
  41. package/dist/lib/chunk-registry-sync.mjs +104 -0
  42. package/dist/lib/chunk-registry-sync.mjs.map +1 -0
  43. package/dist/lib/chunk-run-routine.mjs +57 -0
  44. package/dist/lib/chunk-run-routine.mjs.map +1 -0
  45. package/dist/lib/chunk-templates.mjs +37 -0
  46. package/dist/lib/chunk-templates.mjs.map +1 -0
  47. package/dist/lib/chunk-trigger-runtime-controller.mjs +73 -0
  48. package/dist/lib/chunk-trigger-runtime-controller.mjs.map +1 -0
  49. package/dist/lib/chunk-types.mjs +149 -0
  50. package/dist/lib/chunk-types.mjs.map +1 -0
  51. package/dist/lib/chunk-util.mjs +142 -0
  52. package/dist/lib/chunk-util.mjs.map +1 -0
  53. package/dist/lib/components.mjs +1645 -0
  54. package/dist/lib/components.mjs.map +1 -0
  55. package/dist/lib/containers.mjs +11 -0
  56. package/dist/lib/containers.mjs.map +1 -0
  57. package/dist/lib/hooks.mjs +37 -0
  58. package/dist/lib/hooks.mjs.map +1 -0
  59. package/dist/lib/index.mjs +5 -0
  60. package/dist/lib/meta.mjs +2 -0
  61. package/dist/lib/operations.mjs +7 -0
  62. package/dist/lib/operations.mjs.map +1 -0
  63. package/dist/lib/plugin.mjs +9 -0
  64. package/dist/lib/plugin.mjs.map +1 -0
  65. package/dist/lib/testing.mjs +2 -0
  66. package/dist/lib/translations.mjs +110 -0
  67. package/dist/lib/translations.mjs.map +1 -0
  68. package/dist/lib/types.mjs +2 -0
  69. package/dist/types/src/RoutinePlugin.d.ts.map +1 -1
  70. package/dist/types/src/RoutinePlugin.node.d.ts.map +1 -1
  71. package/dist/types/src/RoutinePlugin.workerd.d.ts.map +1 -1
  72. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  73. package/dist/types/src/capabilities/create-object.d.ts +1 -1
  74. package/dist/types/src/capabilities/index.d.ts +0 -1
  75. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  76. package/dist/types/src/capabilities/layer-specs.d.ts +1 -1
  77. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  78. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  79. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  80. package/dist/types/src/capabilities/registry-sync.d.ts +1 -1
  81. package/dist/types/src/capabilities/templates.d.ts +1 -1
  82. package/dist/types/src/capabilities/trigger-runtime-controller.d.ts +1 -1
  83. package/dist/types/src/commands/trigger/create/{queue.d.ts → feed.d.ts} +2 -2
  84. package/dist/types/src/commands/trigger/create/feed.d.ts.map +1 -0
  85. package/dist/types/src/commands/trigger/update/{queue.d.ts → feed.d.ts} +2 -2
  86. package/dist/types/src/commands/trigger/update/feed.d.ts.map +1 -0
  87. package/dist/types/src/commands/trigger/util.d.ts +1 -1
  88. package/dist/types/src/commands/trigger/util.d.ts.map +1 -1
  89. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.d.ts +7 -5
  90. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.d.ts.map +1 -1
  91. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.stories.d.ts +3 -3
  92. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.stories.d.ts.map +1 -1
  93. package/dist/types/src/components/RoutineCard/RoutineCard.d.ts +9 -0
  94. package/dist/types/src/components/RoutineCard/RoutineCard.d.ts.map +1 -0
  95. package/dist/types/src/components/RoutineCard/RoutineCard.stories.d.ts +21 -0
  96. package/dist/types/src/components/RoutineCard/RoutineCard.stories.d.ts.map +1 -0
  97. package/dist/types/src/components/RoutineCard/index.d.ts +2 -0
  98. package/dist/types/src/components/RoutineCard/index.d.ts.map +1 -0
  99. package/dist/types/src/components/RoutineForm/RoutineForm.d.ts +7 -2
  100. package/dist/types/src/components/RoutineForm/RoutineForm.d.ts.map +1 -1
  101. package/dist/types/src/components/Schedule/Schedule.d.ts +2 -26
  102. package/dist/types/src/components/Schedule/Schedule.d.ts.map +1 -1
  103. package/dist/types/src/components/Schedule/days.d.ts +24 -0
  104. package/dist/types/src/components/Schedule/days.d.ts.map +1 -0
  105. package/dist/types/src/components/Schedule/describe-schedule.d.ts +3 -0
  106. package/dist/types/src/components/Schedule/describe-schedule.d.ts.map +1 -0
  107. package/dist/types/src/components/Schedule/index.d.ts +2 -0
  108. package/dist/types/src/components/Schedule/index.d.ts.map +1 -1
  109. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts +1 -1
  110. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts.map +1 -1
  111. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +1 -2
  112. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
  113. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.d.ts +5 -2
  114. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.d.ts.map +1 -1
  115. package/dist/types/src/components/TriggerEditor/trigger-kind-icon.d.ts +5 -0
  116. package/dist/types/src/components/TriggerEditor/trigger-kind-icon.d.ts.map +1 -0
  117. package/dist/types/src/components/index.d.ts +1 -1
  118. package/dist/types/src/components/index.d.ts.map +1 -1
  119. package/dist/types/src/containers/RoutineArticle/RoutineArticle.d.ts +5 -10
  120. package/dist/types/src/containers/RoutineArticle/RoutineArticle.d.ts.map +1 -1
  121. package/dist/types/src/containers/RoutineArticle/RoutineArticle.stories.d.ts +6 -2
  122. package/dist/types/src/containers/RoutineArticle/RoutineArticle.stories.d.ts.map +1 -1
  123. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.d.ts +4 -12
  124. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.d.ts.map +1 -1
  125. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.stories.d.ts.map +1 -1
  126. package/dist/types/src/containers/RoutineSettings/RoutineSettings.d.ts +4 -8
  127. package/dist/types/src/containers/RoutineSettings/RoutineSettings.d.ts.map +1 -1
  128. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.d.ts +5 -3
  129. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.d.ts.map +1 -1
  130. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.d.ts.map +1 -1
  131. package/dist/types/src/containers/RoutineTraceCompanion/useRoutineRuns.d.ts +1 -1
  132. package/dist/types/src/containers/RoutineTraceCompanion/useRoutineRuns.d.ts.map +1 -1
  133. package/dist/types/src/containers/SkillArticle/SkillArticle.d.ts +4 -1
  134. package/dist/types/src/containers/SkillArticle/SkillArticle.d.ts.map +1 -1
  135. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts +1 -1
  136. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts.map +1 -1
  137. package/dist/types/src/index.d.ts +1 -0
  138. package/dist/types/src/index.d.ts.map +1 -1
  139. package/dist/types/src/operations/run-routine.d.ts.map +1 -1
  140. package/dist/types/src/operations/run-routine.test.d.ts +2 -0
  141. package/dist/types/src/operations/run-routine.test.d.ts.map +1 -0
  142. package/dist/types/src/paths.d.ts.map +1 -1
  143. package/dist/types/src/templates/index.d.ts +1 -1
  144. package/dist/types/src/templates/index.d.ts.map +1 -1
  145. package/dist/types/src/testing/test-functions.d.ts +30 -6
  146. package/dist/types/src/testing/test-functions.d.ts.map +1 -1
  147. package/dist/types/src/translations.d.ts.map +1 -1
  148. package/dist/types/src/types/RoutineCapabilities.d.ts +9 -3
  149. package/dist/types/src/types/RoutineCapabilities.d.ts.map +1 -1
  150. package/dist/types/src/types/RoutineOperation.d.ts +2 -3
  151. package/dist/types/src/types/RoutineOperation.d.ts.map +1 -1
  152. package/dist/types/src/types/index.d.ts +0 -1
  153. package/dist/types/src/types/index.d.ts.map +1 -1
  154. package/dist/types/src/util/index.d.ts +1 -0
  155. package/dist/types/src/util/index.d.ts.map +1 -1
  156. package/dist/types/src/util/routines-for-object.d.ts +6 -3
  157. package/dist/types/src/util/routines-for-object.d.ts.map +1 -1
  158. package/dist/types/src/util/wire.d.ts +21 -0
  159. package/dist/types/src/util/wire.d.ts.map +1 -0
  160. package/dist/types/src/util/wire.test.d.ts +2 -0
  161. package/dist/types/src/util/wire.test.d.ts.map +1 -0
  162. package/dist/types/tsconfig.tsbuildinfo +1 -1
  163. package/dx.config.ts +3 -2
  164. package/package.json +73 -71
  165. package/src/RoutinePlugin.node.ts +1 -2
  166. package/src/RoutinePlugin.tsx +2 -4
  167. package/src/RoutinePlugin.workerd.ts +1 -2
  168. package/src/capabilities/app-graph-builder.ts +9 -7
  169. package/src/capabilities/create-object.ts +2 -2
  170. package/src/capabilities/index.ts +0 -1
  171. package/src/capabilities/layer-specs.ts +78 -12
  172. package/src/capabilities/{react-surface.tsx → react-surface.ts} +18 -22
  173. package/src/capabilities/trigger-runtime-controller.test.ts +12 -18
  174. package/src/capabilities/trigger-runtime-controller.ts +22 -25
  175. package/src/commands/trigger/create/{queue.ts → feed.ts} +1 -1
  176. package/src/commands/trigger/create/index.ts +2 -2
  177. package/src/commands/trigger/update/{queue.ts → feed.ts} +1 -1
  178. package/src/commands/trigger/update/index.ts +2 -2
  179. package/src/commands/trigger/util.ts +1 -2
  180. package/src/components/InstructionsEditor/InstructionsEditor.stories.tsx +7 -6
  181. package/src/components/InstructionsEditor/InstructionsEditor.tsx +31 -19
  182. package/src/components/RoutineCard/RoutineCard.stories.tsx +95 -0
  183. package/src/components/RoutineCard/RoutineCard.tsx +60 -0
  184. package/src/components/{MasterDetail → RoutineCard}/index.ts +1 -1
  185. package/src/components/RoutineForm/RoutineForm.tsx +60 -52
  186. package/src/components/Schedule/Schedule.stories.tsx +1 -1
  187. package/src/components/Schedule/Schedule.tsx +4 -73
  188. package/src/components/Schedule/days.ts +18 -0
  189. package/src/components/Schedule/describe-schedule.ts +64 -0
  190. package/src/components/Schedule/index.ts +2 -0
  191. package/src/components/TemplateEditor/TemplateEditor.stories.tsx +1 -1
  192. package/src/components/TemplateEditor/TemplateForm.tsx +1 -1
  193. package/src/components/TriggerEditor/TriggerEditor.stories.tsx +3 -3
  194. package/src/components/TriggerEditor/TriggerEditor.tsx +79 -66
  195. package/src/components/TriggerEditor/TriggerKindSelector.tsx +4 -30
  196. package/src/components/TriggerEditor/trigger-kind-icon.ts +38 -0
  197. package/src/components/index.ts +1 -1
  198. package/src/containers/RoutineArticle/RoutineArticle.stories.tsx +78 -19
  199. package/src/containers/RoutineArticle/RoutineArticle.tsx +8 -4
  200. package/src/containers/RoutineCompanion/RoutineCompanion.stories.tsx +5 -4
  201. package/src/containers/RoutineCompanion/RoutineCompanion.tsx +11 -7
  202. package/src/containers/RoutineSettings/RoutineSettings.tsx +22 -33
  203. package/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.tsx +6 -5
  204. package/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.tsx +3 -1
  205. package/src/containers/RoutineTraceCompanion/useRoutineRuns.ts +3 -5
  206. package/src/containers/SkillArticle/SkillArticle.tsx +2 -0
  207. package/src/hooks/useTriggerRuntimeControls.ts +2 -2
  208. package/src/index.ts +1 -0
  209. package/src/operations/create-routine.ts +1 -1
  210. package/src/operations/create-trigger-from-template.ts +2 -2
  211. package/src/operations/run-routine.test.ts +150 -0
  212. package/src/operations/run-routine.ts +18 -2
  213. package/src/paths.ts +5 -5
  214. package/src/templates/index.ts +5 -3
  215. package/src/translations.ts +5 -6
  216. package/src/types/RoutineCapabilities.ts +10 -4
  217. package/src/types/RoutineOperation.ts +7 -6
  218. package/src/types/index.ts +0 -1
  219. package/src/util/index.ts +1 -0
  220. package/src/util/routines-for-object.test.ts +37 -5
  221. package/src/util/routines-for-object.ts +33 -8
  222. package/src/util/wire.test.ts +77 -0
  223. package/src/util/wire.ts +76 -0
  224. package/dist/lib/neutral/RoutineArticle-UNTMV4CC.mjs +0 -95
  225. package/dist/lib/neutral/RoutineArticle-UNTMV4CC.mjs.map +0 -7
  226. package/dist/lib/neutral/RoutineCompanion-ZZ6WMY7I.mjs +0 -249
  227. package/dist/lib/neutral/RoutineCompanion-ZZ6WMY7I.mjs.map +0 -7
  228. package/dist/lib/neutral/RoutinePlugin.mjs +0 -10
  229. package/dist/lib/neutral/RoutinePlugin.mjs.map +0 -7
  230. package/dist/lib/neutral/RoutinePlugin.node.mjs +0 -1133
  231. package/dist/lib/neutral/RoutinePlugin.node.mjs.map +0 -7
  232. package/dist/lib/neutral/RoutinePlugin.workerd.mjs +0 -36
  233. package/dist/lib/neutral/RoutinePlugin.workerd.mjs.map +0 -7
  234. package/dist/lib/neutral/RoutineSettings-ZJOM4F3S.mjs +0 -48
  235. package/dist/lib/neutral/RoutineSettings-ZJOM4F3S.mjs.map +0 -7
  236. package/dist/lib/neutral/RoutineTraceCompanion-5U6R7LJE.mjs +0 -236
  237. package/dist/lib/neutral/RoutineTraceCompanion-5U6R7LJE.mjs.map +0 -7
  238. package/dist/lib/neutral/SkillArticle-WWDNKW2Z.mjs +0 -27
  239. package/dist/lib/neutral/SkillArticle-WWDNKW2Z.mjs.map +0 -7
  240. package/dist/lib/neutral/app-graph-builder-FALWLZTI.mjs +0 -90
  241. package/dist/lib/neutral/app-graph-builder-FALWLZTI.mjs.map +0 -7
  242. package/dist/lib/neutral/capabilities/index.mjs +0 -25
  243. package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
  244. package/dist/lib/neutral/capabilities/node.mjs +0 -19
  245. package/dist/lib/neutral/capabilities/node.mjs.map +0 -7
  246. package/dist/lib/neutral/chunk-674LDIUJ.mjs +0 -9
  247. package/dist/lib/neutral/chunk-674LDIUJ.mjs.map +0 -7
  248. package/dist/lib/neutral/chunk-HLO4LYXT.mjs.map +0 -7
  249. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  250. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  251. package/dist/lib/neutral/chunk-P3TDQKOO.mjs +0 -8
  252. package/dist/lib/neutral/chunk-P3TDQKOO.mjs.map +0 -7
  253. package/dist/lib/neutral/chunk-R7J2MU2M.mjs +0 -263
  254. package/dist/lib/neutral/chunk-R7J2MU2M.mjs.map +0 -7
  255. package/dist/lib/neutral/chunk-WLNL77C7.mjs +0 -14
  256. package/dist/lib/neutral/chunk-WLNL77C7.mjs.map +0 -7
  257. package/dist/lib/neutral/chunk-YGWSAKLD.mjs +0 -65
  258. package/dist/lib/neutral/chunk-YGWSAKLD.mjs.map +0 -7
  259. package/dist/lib/neutral/components/index.mjs +0 -1921
  260. package/dist/lib/neutral/components/index.mjs.map +0 -7
  261. package/dist/lib/neutral/containers/index.mjs +0 -17
  262. package/dist/lib/neutral/containers/index.mjs.map +0 -7
  263. package/dist/lib/neutral/create-object-V23KVDMJ.mjs +0 -25
  264. package/dist/lib/neutral/create-object-V23KVDMJ.mjs.map +0 -7
  265. package/dist/lib/neutral/create-routine-6QBY6TWF.mjs +0 -38
  266. package/dist/lib/neutral/create-routine-6QBY6TWF.mjs.map +0 -7
  267. package/dist/lib/neutral/create-trigger-from-template-U3KNS77V.mjs +0 -70
  268. package/dist/lib/neutral/create-trigger-from-template-U3KNS77V.mjs.map +0 -7
  269. package/dist/lib/neutral/hooks/index.mjs +0 -47
  270. package/dist/lib/neutral/hooks/index.mjs.map +0 -7
  271. package/dist/lib/neutral/index.mjs +0 -27
  272. package/dist/lib/neutral/index.mjs.map +0 -7
  273. package/dist/lib/neutral/layer-specs-2TWJU5HI.mjs +0 -135
  274. package/dist/lib/neutral/layer-specs-2TWJU5HI.mjs.map +0 -7
  275. package/dist/lib/neutral/meta.json +0 -1
  276. package/dist/lib/neutral/meta.mjs +0 -8
  277. package/dist/lib/neutral/meta.mjs.map +0 -7
  278. package/dist/lib/neutral/navigation-resolver-KQIWUH6F.mjs +0 -18
  279. package/dist/lib/neutral/navigation-resolver-KQIWUH6F.mjs.map +0 -7
  280. package/dist/lib/neutral/operation-handler-QKLJSDCQ.mjs +0 -13
  281. package/dist/lib/neutral/operation-handler-QKLJSDCQ.mjs.map +0 -7
  282. package/dist/lib/neutral/operations/index.mjs +0 -8
  283. package/dist/lib/neutral/operations/index.mjs.map +0 -7
  284. package/dist/lib/neutral/plugin.mjs +0 -16
  285. package/dist/lib/neutral/plugin.mjs.map +0 -7
  286. package/dist/lib/neutral/react-surface-GMO7I7YE.mjs +0 -67
  287. package/dist/lib/neutral/react-surface-GMO7I7YE.mjs.map +0 -7
  288. package/dist/lib/neutral/registry-sync-DYPOC7ZG.mjs +0 -86
  289. package/dist/lib/neutral/registry-sync-DYPOC7ZG.mjs.map +0 -7
  290. package/dist/lib/neutral/run-routine-AEWO6SYD.mjs +0 -37
  291. package/dist/lib/neutral/run-routine-AEWO6SYD.mjs.map +0 -7
  292. package/dist/lib/neutral/templates-IIUCEBAX.mjs +0 -49
  293. package/dist/lib/neutral/templates-IIUCEBAX.mjs.map +0 -7
  294. package/dist/lib/neutral/testing.mjs +0 -8
  295. package/dist/lib/neutral/testing.mjs.map +0 -7
  296. package/dist/lib/neutral/translations.mjs +0 -115
  297. package/dist/lib/neutral/translations.mjs.map +0 -7
  298. package/dist/lib/neutral/trigger-runtime-controller-WIDDFGQT.mjs +0 -77
  299. package/dist/lib/neutral/trigger-runtime-controller-WIDDFGQT.mjs.map +0 -7
  300. package/dist/lib/neutral/types/index.mjs +0 -17
  301. package/dist/lib/neutral/types/index.mjs.map +0 -7
  302. package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -5
  303. package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
  304. package/dist/types/src/commands/trigger/create/queue.d.ts.map +0 -1
  305. package/dist/types/src/commands/trigger/update/queue.d.ts.map +0 -1
  306. package/dist/types/src/components/MasterDetail/MasterDetail.d.ts +0 -51
  307. package/dist/types/src/components/MasterDetail/MasterDetail.d.ts.map +0 -1
  308. package/dist/types/src/components/MasterDetail/MasterDetail.stories.d.ts +0 -16
  309. package/dist/types/src/components/MasterDetail/MasterDetail.stories.d.ts.map +0 -1
  310. package/dist/types/src/components/MasterDetail/index.d.ts +0 -2
  311. package/dist/types/src/components/MasterDetail/index.d.ts.map +0 -1
  312. package/dist/types/src/types/Routine.d.ts +0 -55
  313. package/dist/types/src/types/Routine.d.ts.map +0 -1
  314. package/dist/types/src/types/Routine.test.d.ts +0 -2
  315. package/dist/types/src/types/Routine.test.d.ts.map +0 -1
  316. package/src/capabilities/navigation-resolver.ts +0 -21
  317. package/src/components/MasterDetail/MasterDetail.stories.tsx +0 -100
  318. package/src/components/MasterDetail/MasterDetail.tsx +0 -175
  319. package/src/types/Routine.test.ts +0 -51
  320. package/src/types/Routine.ts +0 -144
@@ -5,15 +5,15 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import React, { type PropsWithChildren, useCallback, useMemo } from 'react';
7
7
 
8
- import { Instructions, Operation, Trigger } from '@dxos/compute';
8
+ import { Instructions, Operation, Routine, Trigger } from '@dxos/compute';
9
9
  import { type Database, DXN, Entity, Filter, Obj, Query, Ref, Scope, Type } from '@dxos/echo';
10
- import { useObject, useQuery } from '@dxos/react-client/echo';
11
- import { ToggleGroup, ToggleGroupItem, useTranslation } from '@dxos/react-ui';
10
+ import { useObject, useQuery } from '@dxos/echo-react';
11
+ import { ToggleGroup, ToggleGroupItem, composable, composableProps, useTranslation } from '@dxos/react-ui';
12
12
  import { Form, type FormFieldMap, RefField } from '@dxos/react-ui-form';
13
13
 
14
14
  import { meta } from '#meta';
15
- import { Routine } from '#types';
16
15
 
16
+ import { wireTriggers } from '../../util';
17
17
  import { InstructionsEditor } from '../InstructionsEditor';
18
18
  import { TriggerEditor } from '../TriggerEditor';
19
19
 
@@ -45,59 +45,67 @@ export type RoutineFormProps = {
45
45
  * The sub-forms read and autosave the routine's owned instructions and primary trigger directly off the
46
46
  * `routine` graph (live editing); `readonly` displays them without edit affordances. The optional Save/Cancel
47
47
  * row is used only by the companion's create-from-template flow.
48
+ *
49
+ * Created with `composable()` so it carries the COMPOSABLE marker and can be the child of
50
+ * `Panel.Content asChild` (forwards ref and merges layout props onto the scroll viewport).
48
51
  */
49
- export const RoutineForm = ({ db, routine, readonly = false, onSave, onCancel }: RoutineFormProps) => {
50
- const { t } = useTranslation(meta.profile.key);
51
- const [auto, updateAuto] = useObject(routine);
52
- const trigger = usePrimaryTrigger(routine);
52
+ export const RoutineForm = composable<HTMLDivElement, RoutineFormProps>(
53
+ ({ db, routine, readonly = false, onSave, onCancel, ...props }, forwardedRef) => {
54
+ const { t } = useTranslation(meta.profile.key);
55
+ const [auto, updateAuto] = useObject(routine);
56
+ const trigger = usePrimaryTrigger(routine);
53
57
 
54
- // Read once per routine identity; the uncontrolled form owns edits after mount.
55
- const defaultValues = useMemo<Partial<GeneralForm>>(
56
- () => ({ name: auto.name, description: auto.description }),
57
- [routine],
58
- );
59
- const handleValuesChanged = useCallback(
60
- (values: Partial<GeneralForm>) => {
61
- updateAuto((routine) => {
62
- routine.name = values.name;
63
- routine.description = values.description;
64
- });
65
- },
66
- [updateAuto],
67
- );
58
+ // Read once per routine identity; the uncontrolled form owns edits after mount.
59
+ const defaultValues = useMemo<Partial<GeneralForm>>(
60
+ () => ({ name: auto.name, description: auto.description }),
61
+ [routine],
62
+ );
68
63
 
69
- return (
70
- <Form.Root
71
- schema={GeneralForm}
72
- readonly={readonly}
73
- defaultValues={defaultValues}
74
- onValuesChanged={handleValuesChanged}
75
- onSave={onSave}
76
- onCancel={onCancel}
77
- >
78
- <Form.Viewport scroll>
79
- <Form.Content>
80
- <Form.FieldSet />
64
+ const handleValuesChanged = useCallback(
65
+ (values: Partial<GeneralForm>) => {
66
+ updateAuto((routine) => {
67
+ routine.name = values.name;
68
+ routine.description = values.description;
69
+ });
70
+ },
71
+ [updateAuto],
72
+ );
81
73
 
82
- <Section title={t('actions.title')}>
83
- <ActionEditor db={db} routine={routine} readonly={readonly} />
84
- </Section>
74
+ // TODO(burdon): Could this be rewritten a single form with custom fields?
75
+ return (
76
+ <Form.Root
77
+ schema={GeneralForm}
78
+ readonly={readonly}
79
+ defaultValues={defaultValues}
80
+ onValuesChanged={handleValuesChanged}
81
+ onSave={onSave}
82
+ onCancel={onCancel}
83
+ >
84
+ <Form.Viewport scroll {...composableProps(props)} ref={forwardedRef}>
85
+ <Form.Content>
86
+ <Form.FieldSet />
85
87
 
86
- <Section title={t('triggers.title')}>
87
- <TriggerEditor db={db} routine={routine} trigger={trigger} readonly={readonly} />
88
- </Section>
88
+ <Section title={t('actions.title')}>
89
+ <ActionEditor db={db} routine={routine} readonly={readonly} />
90
+ </Section>
89
91
 
90
- {/* Save/Cancel for the edit session (the sub-forms autosave to the in-memory clones as they change). */}
91
- {onSave && <Form.Actions />}
92
- </Form.Content>
93
- </Form.Viewport>
94
- </Form.Root>
95
- );
96
- };
92
+ {/* TODO(burdon): Support multiple triggers. */}
93
+ <Section title={t('triggers.title')}>
94
+ <TriggerEditor db={db} routine={routine} trigger={trigger} readonly={readonly} />
95
+ </Section>
96
+
97
+ {/* Save/Cancel for the edit session (the sub-forms autosave to the in-memory clones as they change). */}
98
+ {onSave && <Form.Actions />}
99
+ </Form.Content>
100
+ </Form.Viewport>
101
+ </Form.Root>
102
+ );
103
+ },
104
+ );
97
105
 
98
106
  /** Lightweight labelled grouping for a sub-form (no `Settings` chrome). */
99
107
  const Section = ({ title, children }: PropsWithChildren<{ title: string }>) => (
100
- <div role='none' className='flex flex-col mbs-4'>
108
+ <div className='flex flex-col mbs-4'>
101
109
  <Form.Label standalone label={title} />
102
110
  {children}
103
111
  </div>
@@ -111,7 +119,7 @@ const Section = ({ title, children }: PropsWithChildren<{ title: string }>) => (
111
119
  * Single action: an Operation (the routine's `spec.runnable`) or an owned Instructions edited inline. The
112
120
  * action kind is derived from the routine's `spec` — an absent spec means "operation, none chosen yet" (a
113
121
  * scaffolded routine always carries an instructions spec, so the only way to clear it is switching to an
114
- * operation). `Routine.make` establishes the owned-instructions wiring when the routine is scaffolded.
122
+ * operation). `makeRoutine` establishes the owned-instructions wiring when the routine is scaffolded.
115
123
  */
116
124
  const ActionEditor = ({
117
125
  db,
@@ -139,7 +147,7 @@ const ActionEditor = ({
139
147
  routine.spec = operation ? { kind: 'runnable', runnable: operation } : undefined;
140
148
  });
141
149
  // Keep the owned trigger's `function`/`input` in sync with the new action.
142
- Routine.wireTriggers(routineProp);
150
+ wireTriggers(routineProp);
143
151
  },
144
152
  [updateRoutine, routineProp],
145
153
  );
@@ -159,13 +167,13 @@ const ActionEditor = ({
159
167
  }
160
168
  });
161
169
  // Re-wire the owned trigger to dispatch the new action (RunInstructions vs the operation).
162
- Routine.wireTriggers(routineProp);
170
+ wireTriggers(routineProp);
163
171
  },
164
172
  [updateRoutine, routineProp],
165
173
  );
166
174
 
167
175
  return (
168
- <div role='none' className='flex flex-col'>
176
+ <div className='flex flex-col'>
169
177
  {!readonly && <ActionKindToggle value={kind} onChange={handleKindChange} />}
170
178
  {kind === 'runnable' ? (
171
179
  <OperationEditor
@@ -17,7 +17,7 @@ const DefaultStory = ({ initial, minInterval }: { initial: ScheduleValue; minInt
17
17
  return (
18
18
  <div className='p-4 flex flex-col gap-3'>
19
19
  <Schedule.Root
20
- classNames='bg-card-surface border border-separator rounded-sm p-2'
20
+ classNames='dx-card-surface border border-separator rounded-sm p-2'
21
21
  timezone='EDT'
22
22
  minInterval={minInterval}
23
23
  value={value}
@@ -18,14 +18,9 @@ import { mx } from '@dxos/ui-theme';
18
18
 
19
19
  import { meta } from '#meta';
20
20
 
21
- import {
22
- MAX_MIN_INTERVAL_SECONDS,
23
- clampSchedule,
24
- describeCron,
25
- fromCron,
26
- scheduleIntervalSeconds,
27
- scheduleToCron,
28
- } from './cron';
21
+ import { MAX_MIN_INTERVAL_SECONDS, clampSchedule, fromCron, scheduleIntervalSeconds, scheduleToCron } from './cron';
22
+ import { type Day, Days } from './days';
23
+ import { describeSchedule } from './describe-schedule';
29
24
 
30
25
  //
31
26
  // Value model.
@@ -40,21 +35,11 @@ export const ScheduleKinds = [
40
35
  'monthly',
41
36
  'custom',
42
37
  ] as const;
38
+
43
39
  export type ScheduleKind = (typeof ScheduleKinds)[number];
44
40
 
45
41
  const isScheduleKind = (value: string): value is ScheduleKind => (ScheduleKinds as readonly string[]).includes(value);
46
42
 
47
- export const Days = [
48
- { value: 'mon', label: 'Mon' },
49
- { value: 'tue', label: 'Tue' },
50
- { value: 'wed', label: 'Wed' },
51
- { value: 'thu', label: 'Thu' },
52
- { value: 'fri', label: 'Fri' },
53
- { value: 'sat', label: 'Sat' },
54
- { value: 'sun', label: 'Sun' },
55
- ] as const;
56
- export type Day = (typeof Days)[number]['value'];
57
-
58
43
  /** Discriminated schedule value. Times are `HH:mm` (24h); `once.date` is `YYYY-MM-DDTHH:mm`. */
59
44
  export type ScheduleValue =
60
45
  // | { kind: 'once'; date?: string }
@@ -471,57 +456,3 @@ const ScheduleEditor = ({ value, onChange }: { value: ScheduleValue; onChange: (
471
456
  //
472
457
  // Summary.
473
458
  //
474
-
475
- const DAY_NAMES: Record<Day, string> = {
476
- mon: 'Monday',
477
- tue: 'Tuesday',
478
- wed: 'Wednesday',
479
- thu: 'Thursday',
480
- fri: 'Friday',
481
- sat: 'Saturday',
482
- sun: 'Sunday',
483
- };
484
-
485
- /** Format a `HH:mm` (24h) time as a 12-hour clock string, e.g. `9:00 AM`. */
486
- const formatTime = (time: string): string => {
487
- const [h, m] = time.split(':').map(Number);
488
- if (Number.isNaN(h) || Number.isNaN(m)) {
489
- return time;
490
- }
491
-
492
- const period = h < 12 ? 'AM' : 'PM';
493
- const hour = h % 12 === 0 ? 12 : h % 12;
494
- return `${hour}:${String(m).padStart(2, '0')} ${period}`;
495
- };
496
-
497
- const withZone = (text: string, timezone?: string): string => (timezone ? `${text} ${timezone}` : text);
498
-
499
- /** Human-readable summary of the schedule, suitable for the header. */
500
- // TODO(wittjosiah): Just use cronstrue for all cases?
501
- export const describeSchedule = (value: ScheduleValue, timezone?: string): string => {
502
- switch (value.kind) {
503
- // case 'once':
504
- // return value.date
505
- // ? `Runs once at ${formatTime(value.date.slice(11))} on ${value.date.slice(0, 10)}`
506
- // : 'Runs once';
507
- case 'hourly':
508
- return `Runs every hour at minute ${value.minute}`;
509
- case 'daily':
510
- return withZone(`Runs every day at ${formatTime(value.time)}`, timezone);
511
- case 'weekly': {
512
- const days =
513
- value.days.length === 0
514
- ? 'no days'
515
- : value.days.length === 1
516
- ? DAY_NAMES[value.days[0]]
517
- : Days.filter((d) => value.days.includes(d.value))
518
- .map((d) => d.label)
519
- .join(', ');
520
- return withZone(`Runs every ${days} at ${formatTime(value.time)}`, timezone);
521
- }
522
- case 'monthly':
523
- return withZone(`Runs monthly on day ${value.day} at ${formatTime(value.time)}`, timezone);
524
- case 'custom':
525
- return withZone(describeCron(value.cron), timezone);
526
- }
527
- };
@@ -0,0 +1,18 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ // Shared by `Schedule.tsx` and `describe-schedule.ts`: a value import between those two would close a
6
+ // runtime cycle, and react-refresh only fast-refreshes a module whose exports are all components.
7
+
8
+ export const Days = [
9
+ { value: 'mon', label: 'Mon' },
10
+ { value: 'tue', label: 'Tue' },
11
+ { value: 'wed', label: 'Wed' },
12
+ { value: 'thu', label: 'Thu' },
13
+ { value: 'fri', label: 'Fri' },
14
+ { value: 'sat', label: 'Sat' },
15
+ { value: 'sun', label: 'Sun' },
16
+ ] as const;
17
+
18
+ export type Day = (typeof Days)[number]['value'];
@@ -0,0 +1,64 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describeCron } from './cron';
6
+ import { type Day, Days } from './days';
7
+ import { type ScheduleValue } from './Schedule';
8
+
9
+ // Kept out of `Schedule.tsx`: react-refresh only fast-refreshes a module whose
10
+ // exports are all components, so values exported beside them force a full page reload on
11
+ // every edit.
12
+
13
+ /** Human-readable summary of the schedule, suitable for the header. */
14
+ // TODO(wittjosiah): Just use cronstrue for all cases?
15
+ const DAY_NAMES: Record<Day, string> = {
16
+ mon: 'Monday',
17
+ tue: 'Tuesday',
18
+ wed: 'Wednesday',
19
+ thu: 'Thursday',
20
+ fri: 'Friday',
21
+ sat: 'Saturday',
22
+ sun: 'Sunday',
23
+ };
24
+
25
+ const withZone = (text: string, timezone?: string): string => (timezone ? `${text} ${timezone}` : text);
26
+
27
+ const formatTime = (time: string): string => {
28
+ const [h, m] = time.split(':').map(Number);
29
+ if (Number.isNaN(h) || Number.isNaN(m)) {
30
+ return time;
31
+ }
32
+
33
+ const period = h < 12 ? 'AM' : 'PM';
34
+ const hour = h % 12 === 0 ? 12 : h % 12;
35
+ return `${hour}:${String(m).padStart(2, '0')} ${period}`;
36
+ };
37
+
38
+ export const describeSchedule = (value: ScheduleValue, timezone?: string): string => {
39
+ switch (value.kind) {
40
+ // case 'once':
41
+ // return value.date
42
+ // ? `Runs once at ${formatTime(value.date.slice(11))} on ${value.date.slice(0, 10)}`
43
+ // : 'Runs once';
44
+ case 'hourly':
45
+ return `Runs every hour at minute ${value.minute}`;
46
+ case 'daily':
47
+ return withZone(`Runs every day at ${formatTime(value.time)}`, timezone);
48
+ case 'weekly': {
49
+ const days =
50
+ value.days.length === 0
51
+ ? 'no days'
52
+ : value.days.length === 1
53
+ ? DAY_NAMES[value.days[0]]
54
+ : Days.filter((d) => value.days.includes(d.value))
55
+ .map((d) => d.label)
56
+ .join(', ');
57
+ return withZone(`Runs every ${days} at ${formatTime(value.time)}`, timezone);
58
+ }
59
+ case 'monthly':
60
+ return withZone(`Runs monthly on day ${value.day} at ${formatTime(value.time)}`, timezone);
61
+ case 'custom':
62
+ return withZone(describeCron(value.cron), timezone);
63
+ }
64
+ };
@@ -5,4 +5,6 @@
5
5
  export * from './cron';
6
6
  export * from './types';
7
7
 
8
+ export * from './days';
9
+ export * from './describe-schedule';
8
10
  export * from './Schedule';
@@ -55,7 +55,7 @@ const DefaultStory = ({ source }: TemplateEditorProps & { source: string }) => {
55
55
  );
56
56
  });
57
57
 
58
- return <TemplateEditor classNames='dx-document bg-base-surface' id={skill.id} source={skill.instructions.source} />;
58
+ return <TemplateEditor classNames='dx-document dx-base-surface' id={skill.id} source={skill.instructions.source} />;
59
59
  };
60
60
 
61
61
  const meta = {
@@ -60,7 +60,7 @@ export const TemplateForm = ({ id, template, onChange }: TemplateFormProps) => {
60
60
 
61
61
  return (
62
62
  <div className='flex flex-col w-full overflow-hidden gap-4'>
63
- <TemplateEditor id={id} source={template.source} classNames='bg-base-surface min-h-[120px]' />
63
+ <TemplateEditor id={id} source={template.source} classNames='dx-base-surface min-h-[120px]' />
64
64
 
65
65
  {(template.inputs?.length ?? 0) > 0 && (
66
66
  <div className='grid grid-cols-[10rem_10rem_1fr] gap-1 items-center'>
@@ -6,14 +6,14 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
  import { expect, userEvent, within } from 'storybook/test';
8
8
 
9
- import { Trigger } from '@dxos/compute';
9
+ import { Routine, Trigger } from '@dxos/compute';
10
10
  import { Feed, Filter, Obj } from '@dxos/echo';
11
- import { type Space, useQuery } from '@dxos/react-client/echo';
11
+ import { useQuery } from '@dxos/echo-react';
12
+ import { type Space } from '@dxos/react-client/echo';
12
13
  import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
13
14
  import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
14
15
 
15
16
  import { translations } from '#translations';
16
- import { Routine } from '#types';
17
17
 
18
18
  import { TriggerEditor } from './TriggerEditor';
19
19
 
@@ -5,17 +5,17 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import React, { useCallback, useMemo, useState } from 'react';
7
7
 
8
- import { Trigger } from '@dxos/compute';
8
+ import { Routine, Trigger } from '@dxos/compute';
9
9
  import { type Database, DXN, Feed, Filter, Obj, Query, Ref, Scope, Type } from '@dxos/echo';
10
- import { useQuery } from '@dxos/react-client/echo';
10
+ import { useQuery } from '@dxos/echo-react';
11
11
  import { IconButton, Input, ThemedClassName, useTranslation } from '@dxos/react-ui';
12
12
  import { Form, type FormFieldMap, type FormFieldRendererProps, SelectField } from '@dxos/react-ui-form';
13
13
  import { ParentLabelAnnotation } from '@dxos/schema';
14
14
  import { mx } from '@dxos/ui-theme';
15
15
 
16
16
  import { meta } from '#meta';
17
- import { Routine } from '#types';
18
17
 
18
+ import { wireTriggers } from '../../util';
19
19
  import {
20
20
  FrequencyDefaults,
21
21
  Schedule,
@@ -30,10 +30,8 @@ import { type TriggerKind, TriggerKindSelector } from './TriggerKindSelector';
30
30
  // A recurring trigger fires on a cron, so the one-time `once` kind is not offered here.
31
31
  const RECURRING_KINDS = ['hourly', 'daily', 'weekly', 'monthly', 'custom'] as const satisfies readonly ScheduleKind[];
32
32
 
33
- // The `enabled` toggle is a field of the Trigger object (sibling of `spec`), not of any spec variant. It is
34
- // reused from the Trigger schema (rather than redeclared) and extended onto every form member so the editor
35
- // surfaces it once a kind is chosen; the value is written back to `trigger.enabled`, not the spec.
36
- const EnabledForm = Type.getSchema(Trigger.Trigger).pipe(Schema.pick('enabled'));
33
+ // `enabled` is extended onto every spec form so it renders inline with the kind's fields.
34
+ const EnabledForm = Type.getSchema(Trigger.Trigger).pipe(Schema.pick('enabled', 'remote'));
37
35
 
38
36
  // Scoped trigger form, modeled as a top-level discriminated union (one member per pluggable variant) so the
39
37
  // Form renders the chosen kind's fields as one flat field set (no nested, bordered sub-fieldset). The kind
@@ -186,50 +184,51 @@ export type TriggerEditorProps = ThemedClassName<{
186
184
 
187
185
  export const TriggerEditor = ({ classNames, db, routine, trigger, readonly }: TriggerEditorProps) => {
188
186
  const { t } = useTranslation(meta.profile.key);
189
- const { defaultValues, fieldMap, kind, resetNonce, handleClose, handleValuesChanged } = useTriggerForm(
190
- routine,
191
- trigger,
192
- );
187
+ const { defaultValues, fieldMap, kind, reset, handleValuesChanged } = useTriggerForm(routine, trigger);
193
188
 
194
- // TODO(burdon): Not persistent; need to memo
195
189
  return (
196
- <Form.Root
197
- // Remount when the bound trigger changes (picks up its spec) or on reset (reverts to the picker).
198
- key={`${trigger?.id ?? 'new'}:${resetNonce}`}
199
- schema={TriggerForm}
200
- db={db}
201
- readonly={readonly}
202
- fieldMap={fieldMap}
203
- defaultValues={defaultValues}
204
- onValuesChanged={handleValuesChanged}
205
- >
206
- <Form.Content classNames={mx(kind && 'pb-2 bg-card-surface border border-separator rounded-xs', classNames)}>
207
- {/* TODO(burdon): Generalize indented section for discriminated unions. */}
208
- {(kind && (
209
- <>
210
- <div className='flex items-center'>
211
- <Input.Root>
212
- <Input.Label classNames='pl-2 grow truncate'>{t(`trigger-kind.${kind}.label`)}</Input.Label>
213
- </Input.Root>
214
- {!readonly && (
215
- <IconButton
216
- iconOnly
217
- variant='ghost'
218
- square
219
- icon='ph--x--regular'
220
- label={t('trigger-kind.clear.label')}
221
- onClick={handleClose}
222
- />
223
- )}
224
- </div>
225
- <Form.FieldSet classNames='px-2' />
226
- </>
227
- )) || <Form.FieldSet />}
228
-
229
- {/* Email triggers have no configuration; surface an explanatory note instead of an empty body. */}
230
- {kind === 'email' && <p className='px-2 text-sm text-description'>{t('trigger-kind.email-note.message')}</p>}
231
- </Form.Content>
232
- </Form.Root>
190
+ <>
191
+ <Form.Root
192
+ // Remount when the bound trigger changes or its spec kind changes (including reset to no kind),
193
+ // so the uncontrolled form re-reads `defaultValues`; stable while editing fields within a kind.
194
+ key={`${trigger?.id ?? 'new'}:${trigger?.spec?.kind ?? 'none'}`}
195
+ schema={TriggerForm}
196
+ db={db}
197
+ readonly={readonly}
198
+ fieldMap={fieldMap}
199
+ defaultValues={defaultValues}
200
+ onValuesChanged={handleValuesChanged}
201
+ >
202
+ {/* TODO(burdon): Generalize Form handling (indented section) for discriminated unions. */}
203
+ <Form.Content classNames={mx(kind && 'pb-2 dx-card-surface border border-separator rounded-xs', classNames)}>
204
+ {kind ? (
205
+ <>
206
+ <div className='flex items-center'>
207
+ <Input.Root>
208
+ <Input.Label classNames='pl-2 grow truncate'>{t(`trigger-kind.${kind}.label`)}</Input.Label>
209
+ </Input.Root>
210
+ {!readonly && (
211
+ <IconButton
212
+ variant='ghost'
213
+ icon='ph--x--regular'
214
+ iconOnly
215
+ square
216
+ label={t('trigger-kind.clear.label')}
217
+ onClick={reset}
218
+ />
219
+ )}
220
+ </div>
221
+ <Form.FieldSet classNames='px-2' />
222
+ </>
223
+ ) : (
224
+ <Form.FieldSet />
225
+ )}
226
+
227
+ {/* Currently, email triggers have no configuration; surface an explanatory note instead of an empty body. */}
228
+ {kind === 'email' && <p className='px-2 text-sm text-description'>{t('trigger-kind.email-note.message')}</p>}
229
+ </Form.Content>
230
+ </Form.Root>
231
+ </>
233
232
  );
234
233
  };
235
234
 
@@ -301,22 +300,25 @@ const useTriggerForm = (routine: Routine.Routine, trigger?: Trigger.Trigger) =>
301
300
  [methodOptions],
302
301
  );
303
302
 
304
- // Bumping this remounts the uncontrolled Form so it re-reads `defaultValues` (used to revert to the picker).
305
- const [resetNonce, setResetNonce] = useState(0);
306
- // Read per trigger identity / reset; a trigger with no spec yet starts with no kind (shows the picker).
307
- // `enabled` is a Trigger-level field, seeded alongside the spec-derived variant values.
303
+ // Seed from the trigger's current spec/enabled; a trigger with no spec starts with no kind (picker).
304
+ // Depend on `spec`/`enabled` (not just `trigger` identity) so an in-place clear/change recomputes the
305
+ // seed — the Form re-reads it on remount (keyed by `spec.kind`), reverting to the picker on reset.
308
306
  const defaultValues = useMemo<Partial<TriggerFormValues>>(
309
- () => ({ ...triggerFormValues(trigger?.spec), enabled: trigger?.enabled }),
310
- [trigger, resetNonce],
307
+ () => ({
308
+ ...triggerFormValues(trigger?.spec),
309
+ enabled: trigger?.enabled,
310
+ remote: trigger?.remote,
311
+ }),
312
+ [trigger, trigger?.spec, trigger?.enabled, trigger?.remote],
311
313
  );
312
314
 
313
315
  // Mirror the active kind: gates the variant picker (shown only while unset) and the variant-specific notes.
314
316
  const [kind, setKind] = useState<TriggerKind | undefined>(() => triggerFormValues(trigger?.spec).kind);
315
317
 
316
- // Revert the kind selection: clear the trigger's spec and remount the Form so the picker reappears.
317
- const handleClose = useCallback(() => {
318
+ // Revert the kind selection: clear the trigger's spec. Clearing changes `spec.kind`, which is part of
319
+ // the Form's `key`, so the form remounts and re-reads `defaultValues` (picker reappears) — no nonce needed.
320
+ const reset = useCallback(() => {
318
321
  setKind(undefined);
319
- setResetNonce((nonce) => nonce + 1);
320
322
  if (trigger) {
321
323
  Obj.update(trigger, (trigger) => {
322
324
  trigger.spec = undefined;
@@ -332,11 +334,15 @@ const useTriggerForm = (routine: Routine.Routine, trigger?: Trigger.Trigger) =>
332
334
  }
333
335
 
334
336
  const spec = triggerFormSpec(values);
335
- setKind(spec.kind);
337
+ // `triggerFormSpec` maps `values.kind` 1:1 onto `spec.kind`; use the already-narrowed form kind so
338
+ // the state stays typed as the selectable `TriggerKind` subset (the wider `Trigger.Spec` union now
339
+ // also carries the invoke-only `manual` kind, which the form never produces).
340
+ setKind(values.kind);
336
341
  const enabled = values.enabled === true;
337
- // Edit the spec and `enabled` on the trigger; the trigger's `function` and `input` (including the
338
- // instructions binding and any operation-specific bindings like `{ magazine }`) are wired once by
339
- // `Routine.make`, so they are not re-derived here.
342
+ const remote = values.remote;
343
+ // Edit the spec, `enabled`, and `remote` on the trigger directly from the form values.
344
+ // The trigger's `function` and `input` (including the instructions binding and any operation-specific
345
+ // bindings like `{ magazine }`) are wired once by `makeRoutine`, so they are not re-derived here.
340
346
  if (trigger) {
341
347
  Obj.update(trigger, (trigger) => {
342
348
  // The subscription spec's QueryAST is deeply readonly while the live ECHO draft's `spec` is mutable;
@@ -344,22 +350,29 @@ const useTriggerForm = (routine: Routine.Routine, trigger?: Trigger.Trigger) =>
344
350
  // (mirrors commands/trigger/update/subscription.ts).
345
351
  trigger.spec = spec as typeof trigger.spec;
346
352
  trigger.enabled = enabled;
353
+ trigger.remote = remote;
347
354
  });
348
355
  } else {
349
- // Defensive: the draft normally carries an owned trigger already (see `Routine.make`). If absent,
356
+ // Defensive: the draft normally carries an owned trigger already (see `makeRoutine`). If absent,
350
357
  // create one in memory and attach it to the routine graph — nothing is persisted until save.
351
- const created = Trigger.make({ spec, enabled });
358
+ const created = Trigger.make({ spec, enabled, remote });
352
359
  Obj.setParent(created, routine);
353
360
  Obj.update(routine, (routine) => {
354
361
  routine.triggers.push(Ref.make(created));
355
362
  });
356
363
  // Wire the new trigger's `function`/`input` to dispatch the routine's action (RunInstructions binds the
357
364
  // owned instructions; an operation binds directly).
358
- Routine.wireTriggers(routine);
365
+ wireTriggers(routine);
359
366
  }
360
367
  },
361
368
  [routine, trigger],
362
369
  );
363
370
 
364
- return { defaultValues, fieldMap, kind, resetNonce, handleClose, handleValuesChanged };
371
+ return {
372
+ defaultValues,
373
+ fieldMap,
374
+ kind,
375
+ reset,
376
+ handleValuesChanged,
377
+ };
365
378
  };