@dxos/plugin-routine 0.0.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 (403) hide show
  1. package/LICENSE +105 -0
  2. package/PLUGIN.mdl +475 -0
  3. package/README.md +15 -0
  4. package/dist/lib/neutral/RoutineArticle-UNTMV4CC.mjs +95 -0
  5. package/dist/lib/neutral/RoutineArticle-UNTMV4CC.mjs.map +7 -0
  6. package/dist/lib/neutral/RoutineCompanion-ZZ6WMY7I.mjs +249 -0
  7. package/dist/lib/neutral/RoutineCompanion-ZZ6WMY7I.mjs.map +7 -0
  8. package/dist/lib/neutral/RoutinePlugin.mjs +10 -0
  9. package/dist/lib/neutral/RoutinePlugin.mjs.map +7 -0
  10. package/dist/lib/neutral/RoutinePlugin.node.mjs +1133 -0
  11. package/dist/lib/neutral/RoutinePlugin.node.mjs.map +7 -0
  12. package/dist/lib/neutral/RoutinePlugin.workerd.mjs +36 -0
  13. package/dist/lib/neutral/RoutinePlugin.workerd.mjs.map +7 -0
  14. package/dist/lib/neutral/RoutineSettings-ZJOM4F3S.mjs +48 -0
  15. package/dist/lib/neutral/RoutineSettings-ZJOM4F3S.mjs.map +7 -0
  16. package/dist/lib/neutral/RoutineTraceCompanion-5U6R7LJE.mjs +236 -0
  17. package/dist/lib/neutral/RoutineTraceCompanion-5U6R7LJE.mjs.map +7 -0
  18. package/dist/lib/neutral/SkillArticle-WWDNKW2Z.mjs +27 -0
  19. package/dist/lib/neutral/SkillArticle-WWDNKW2Z.mjs.map +7 -0
  20. package/dist/lib/neutral/app-graph-builder-FALWLZTI.mjs +90 -0
  21. package/dist/lib/neutral/app-graph-builder-FALWLZTI.mjs.map +7 -0
  22. package/dist/lib/neutral/capabilities/index.mjs +25 -0
  23. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  24. package/dist/lib/neutral/capabilities/node.mjs +19 -0
  25. package/dist/lib/neutral/capabilities/node.mjs.map +7 -0
  26. package/dist/lib/neutral/chunk-674LDIUJ.mjs +9 -0
  27. package/dist/lib/neutral/chunk-674LDIUJ.mjs.map +7 -0
  28. package/dist/lib/neutral/chunk-CNYAPXUW.mjs +65 -0
  29. package/dist/lib/neutral/chunk-CNYAPXUW.mjs.map +7 -0
  30. package/dist/lib/neutral/chunk-HLO4LYXT.mjs +44 -0
  31. package/dist/lib/neutral/chunk-HLO4LYXT.mjs.map +7 -0
  32. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  33. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
  34. package/dist/lib/neutral/chunk-ODQDVFMZ.mjs +8 -0
  35. package/dist/lib/neutral/chunk-ODQDVFMZ.mjs.map +7 -0
  36. package/dist/lib/neutral/chunk-R7J2MU2M.mjs +263 -0
  37. package/dist/lib/neutral/chunk-R7J2MU2M.mjs.map +7 -0
  38. package/dist/lib/neutral/chunk-WLNL77C7.mjs +14 -0
  39. package/dist/lib/neutral/chunk-WLNL77C7.mjs.map +7 -0
  40. package/dist/lib/neutral/components/index.mjs +1921 -0
  41. package/dist/lib/neutral/components/index.mjs.map +7 -0
  42. package/dist/lib/neutral/containers/index.mjs +17 -0
  43. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  44. package/dist/lib/neutral/create-object-V23KVDMJ.mjs +25 -0
  45. package/dist/lib/neutral/create-object-V23KVDMJ.mjs.map +7 -0
  46. package/dist/lib/neutral/create-routine-I67BYJA2.mjs +38 -0
  47. package/dist/lib/neutral/create-routine-I67BYJA2.mjs.map +7 -0
  48. package/dist/lib/neutral/create-trigger-from-template-U3KNS77V.mjs +70 -0
  49. package/dist/lib/neutral/create-trigger-from-template-U3KNS77V.mjs.map +7 -0
  50. package/dist/lib/neutral/hooks/index.mjs +47 -0
  51. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  52. package/dist/lib/neutral/index.mjs +27 -0
  53. package/dist/lib/neutral/index.mjs.map +7 -0
  54. package/dist/lib/neutral/layer-specs-ADQCTTRT.mjs +135 -0
  55. package/dist/lib/neutral/layer-specs-ADQCTTRT.mjs.map +7 -0
  56. package/dist/lib/neutral/meta.json +1 -0
  57. package/dist/lib/neutral/meta.mjs +8 -0
  58. package/dist/lib/neutral/meta.mjs.map +7 -0
  59. package/dist/lib/neutral/navigation-resolver-KQIWUH6F.mjs +18 -0
  60. package/dist/lib/neutral/navigation-resolver-KQIWUH6F.mjs.map +7 -0
  61. package/dist/lib/neutral/operation-handler-QKLJSDCQ.mjs +13 -0
  62. package/dist/lib/neutral/operation-handler-QKLJSDCQ.mjs.map +7 -0
  63. package/dist/lib/neutral/operations/index.mjs +8 -0
  64. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  65. package/dist/lib/neutral/plugin.mjs +16 -0
  66. package/dist/lib/neutral/plugin.mjs.map +7 -0
  67. package/dist/lib/neutral/react-surface-GMO7I7YE.mjs +67 -0
  68. package/dist/lib/neutral/react-surface-GMO7I7YE.mjs.map +7 -0
  69. package/dist/lib/neutral/registry-sync-PHBU6CH2.mjs +86 -0
  70. package/dist/lib/neutral/registry-sync-PHBU6CH2.mjs.map +7 -0
  71. package/dist/lib/neutral/run-routine-HJWXIWLJ.mjs +37 -0
  72. package/dist/lib/neutral/run-routine-HJWXIWLJ.mjs.map +7 -0
  73. package/dist/lib/neutral/templates-IIUCEBAX.mjs +49 -0
  74. package/dist/lib/neutral/templates-IIUCEBAX.mjs.map +7 -0
  75. package/dist/lib/neutral/testing.mjs +8 -0
  76. package/dist/lib/neutral/testing.mjs.map +7 -0
  77. package/dist/lib/neutral/translations.mjs +115 -0
  78. package/dist/lib/neutral/translations.mjs.map +7 -0
  79. package/dist/lib/neutral/trigger-runtime-controller-7FOTH2NP.mjs +77 -0
  80. package/dist/lib/neutral/trigger-runtime-controller-7FOTH2NP.mjs.map +7 -0
  81. package/dist/lib/neutral/types/index.mjs +17 -0
  82. package/dist/lib/neutral/types/index.mjs.map +7 -0
  83. package/dist/types/dx.config.d.ts +28 -0
  84. package/dist/types/dx.config.d.ts.map +1 -0
  85. package/dist/types/src/RoutinePlugin.d.ts +4 -0
  86. package/dist/types/src/RoutinePlugin.d.ts.map +1 -0
  87. package/dist/types/src/RoutinePlugin.node.d.ts +4 -0
  88. package/dist/types/src/RoutinePlugin.node.d.ts.map +1 -0
  89. package/dist/types/src/RoutinePlugin.test.d.ts +2 -0
  90. package/dist/types/src/RoutinePlugin.test.d.ts.map +1 -0
  91. package/dist/types/src/RoutinePlugin.workerd.d.ts +4 -0
  92. package/dist/types/src/RoutinePlugin.workerd.d.ts.map +1 -0
  93. package/dist/types/src/capabilities/app-graph-builder.d.ts +5 -0
  94. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  95. package/dist/types/src/capabilities/create-object.d.ts +5 -0
  96. package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
  97. package/dist/types/src/capabilities/create-object.test.d.ts +2 -0
  98. package/dist/types/src/capabilities/create-object.test.d.ts.map +1 -0
  99. package/dist/types/src/capabilities/index.d.ts +12 -0
  100. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  101. package/dist/types/src/capabilities/layer-specs.d.ts +5 -0
  102. package/dist/types/src/capabilities/layer-specs.d.ts.map +1 -0
  103. package/dist/types/src/capabilities/navigation-resolver.d.ts +5 -0
  104. package/dist/types/src/capabilities/navigation-resolver.d.ts.map +1 -0
  105. package/dist/types/src/capabilities/node.d.ts +9 -0
  106. package/dist/types/src/capabilities/node.d.ts.map +1 -0
  107. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  108. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  109. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  110. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  111. package/dist/types/src/capabilities/registry-sync.d.ts +21 -0
  112. package/dist/types/src/capabilities/registry-sync.d.ts.map +1 -0
  113. package/dist/types/src/capabilities/templates.d.ts +5 -0
  114. package/dist/types/src/capabilities/templates.d.ts.map +1 -0
  115. package/dist/types/src/capabilities/trigger-runtime-controller.d.ts +5 -0
  116. package/dist/types/src/capabilities/trigger-runtime-controller.d.ts.map +1 -0
  117. package/dist/types/src/capabilities/trigger-runtime-controller.test.d.ts +2 -0
  118. package/dist/types/src/capabilities/trigger-runtime-controller.test.d.ts.map +1 -0
  119. package/dist/types/src/commands/index.d.ts +2 -0
  120. package/dist/types/src/commands/index.d.ts.map +1 -0
  121. package/dist/types/src/commands/trigger/create/index.d.ts +25 -0
  122. package/dist/types/src/commands/trigger/create/index.d.ts.map +1 -0
  123. package/dist/types/src/commands/trigger/create/queue.d.ts +13 -0
  124. package/dist/types/src/commands/trigger/create/queue.d.ts.map +1 -0
  125. package/dist/types/src/commands/trigger/create/subscription.d.ts +15 -0
  126. package/dist/types/src/commands/trigger/create/subscription.d.ts.map +1 -0
  127. package/dist/types/src/commands/trigger/create/timer.d.ts +13 -0
  128. package/dist/types/src/commands/trigger/create/timer.d.ts.map +1 -0
  129. package/dist/types/src/commands/trigger/index.d.ts +57 -0
  130. package/dist/types/src/commands/trigger/index.d.ts.map +1 -0
  131. package/dist/types/src/commands/trigger/list.d.ts +7 -0
  132. package/dist/types/src/commands/trigger/list.d.ts.map +1 -0
  133. package/dist/types/src/commands/trigger/options.d.ts +10 -0
  134. package/dist/types/src/commands/trigger/options.d.ts.map +1 -0
  135. package/dist/types/src/commands/trigger/remove.d.ts +8 -0
  136. package/dist/types/src/commands/trigger/remove.d.ts.map +1 -0
  137. package/dist/types/src/commands/trigger/update/index.d.ts +28 -0
  138. package/dist/types/src/commands/trigger/update/index.d.ts.map +1 -0
  139. package/dist/types/src/commands/trigger/update/queue.d.ts +13 -0
  140. package/dist/types/src/commands/trigger/update/queue.d.ts.map +1 -0
  141. package/dist/types/src/commands/trigger/update/subscription.d.ts +15 -0
  142. package/dist/types/src/commands/trigger/update/subscription.d.ts.map +1 -0
  143. package/dist/types/src/commands/trigger/update/timer.d.ts +13 -0
  144. package/dist/types/src/commands/trigger/update/timer.d.ts.map +1 -0
  145. package/dist/types/src/commands/trigger/util.d.ts +46 -0
  146. package/dist/types/src/commands/trigger/util.d.ts.map +1 -0
  147. package/dist/types/src/components/CreateRoutinePanel/CreateRoutinePanel.d.ts +14 -0
  148. package/dist/types/src/components/CreateRoutinePanel/CreateRoutinePanel.d.ts.map +1 -0
  149. package/dist/types/src/components/CreateRoutinePanel/index.d.ts +2 -0
  150. package/dist/types/src/components/CreateRoutinePanel/index.d.ts.map +1 -0
  151. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.d.ts +16 -0
  152. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.d.ts.map +1 -0
  153. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.stories.d.ts +17 -0
  154. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.stories.d.ts.map +1 -0
  155. package/dist/types/src/components/InstructionsEditor/index.d.ts +2 -0
  156. package/dist/types/src/components/InstructionsEditor/index.d.ts.map +1 -0
  157. package/dist/types/src/components/MasterDetail/MasterDetail.d.ts +51 -0
  158. package/dist/types/src/components/MasterDetail/MasterDetail.d.ts.map +1 -0
  159. package/dist/types/src/components/MasterDetail/MasterDetail.stories.d.ts +16 -0
  160. package/dist/types/src/components/MasterDetail/MasterDetail.stories.d.ts.map +1 -0
  161. package/dist/types/src/components/MasterDetail/index.d.ts +2 -0
  162. package/dist/types/src/components/MasterDetail/index.d.ts.map +1 -0
  163. package/dist/types/src/components/RoutineForm/RoutineForm.d.ts +25 -0
  164. package/dist/types/src/components/RoutineForm/RoutineForm.d.ts.map +1 -0
  165. package/dist/types/src/components/RoutineForm/index.d.ts +2 -0
  166. package/dist/types/src/components/RoutineForm/index.d.ts.map +1 -0
  167. package/dist/types/src/components/Schedule/Schedule.d.ts +80 -0
  168. package/dist/types/src/components/Schedule/Schedule.d.ts.map +1 -0
  169. package/dist/types/src/components/Schedule/Schedule.stories.d.ts +23 -0
  170. package/dist/types/src/components/Schedule/Schedule.stories.d.ts.map +1 -0
  171. package/dist/types/src/components/Schedule/cron.d.ts +44 -0
  172. package/dist/types/src/components/Schedule/cron.d.ts.map +1 -0
  173. package/dist/types/src/components/Schedule/cron.test.d.ts +2 -0
  174. package/dist/types/src/components/Schedule/cron.test.d.ts.map +1 -0
  175. package/dist/types/src/components/Schedule/index.d.ts +4 -0
  176. package/dist/types/src/components/Schedule/index.d.ts.map +1 -0
  177. package/dist/types/src/components/Schedule/types.d.ts +66 -0
  178. package/dist/types/src/components/Schedule/types.d.ts.map +1 -0
  179. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts +13 -0
  180. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts.map +1 -0
  181. package/dist/types/src/components/TemplateEditor/TemplateEditor.stories.d.ts +19 -0
  182. package/dist/types/src/components/TemplateEditor/TemplateEditor.stories.d.ts.map +1 -0
  183. package/dist/types/src/components/TemplateEditor/TemplateForm.d.ts +21 -0
  184. package/dist/types/src/components/TemplateEditor/TemplateForm.d.ts.map +1 -0
  185. package/dist/types/src/components/TemplateEditor/TemplateForm.stories.d.ts +16 -0
  186. package/dist/types/src/components/TemplateEditor/TemplateForm.stories.d.ts.map +1 -0
  187. package/dist/types/src/components/TemplateEditor/extensions/handlebars-extension.d.ts +12 -0
  188. package/dist/types/src/components/TemplateEditor/extensions/handlebars-extension.d.ts.map +1 -0
  189. package/dist/types/src/components/TemplateEditor/extensions/index.d.ts +3 -0
  190. package/dist/types/src/components/TemplateEditor/extensions/index.d.ts.map +1 -0
  191. package/dist/types/src/components/TemplateEditor/extensions/xml-extension.d.ts +8 -0
  192. package/dist/types/src/components/TemplateEditor/extensions/xml-extension.d.ts.map +1 -0
  193. package/dist/types/src/components/TemplateEditor/index.d.ts +2 -0
  194. package/dist/types/src/components/TemplateEditor/index.d.ts.map +1 -0
  195. package/dist/types/src/components/TemplateEditor/types.d.ts +18 -0
  196. package/dist/types/src/components/TemplateEditor/types.d.ts.map +1 -0
  197. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +24 -0
  198. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -0
  199. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts +25 -0
  200. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -0
  201. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.d.ts +15 -0
  202. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.d.ts.map +1 -0
  203. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.stories.d.ts +15 -0
  204. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.stories.d.ts.map +1 -0
  205. package/dist/types/src/components/TriggerEditor/index.d.ts +2 -0
  206. package/dist/types/src/components/TriggerEditor/index.d.ts.map +1 -0
  207. package/dist/types/src/components/index.d.ts +8 -0
  208. package/dist/types/src/components/index.d.ts.map +1 -0
  209. package/dist/types/src/containers/RoutineArticle/RoutineArticle.d.ts +14 -0
  210. package/dist/types/src/containers/RoutineArticle/RoutineArticle.d.ts.map +1 -0
  211. package/dist/types/src/containers/RoutineArticle/RoutineArticle.stories.d.ts +20 -0
  212. package/dist/types/src/containers/RoutineArticle/RoutineArticle.stories.d.ts.map +1 -0
  213. package/dist/types/src/containers/RoutineArticle/index.d.ts +2 -0
  214. package/dist/types/src/containers/RoutineArticle/index.d.ts.map +1 -0
  215. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.d.ts +17 -0
  216. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.d.ts.map +1 -0
  217. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.stories.d.ts +15 -0
  218. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.stories.d.ts.map +1 -0
  219. package/dist/types/src/containers/RoutineCompanion/index.d.ts +3 -0
  220. package/dist/types/src/containers/RoutineCompanion/index.d.ts.map +1 -0
  221. package/dist/types/src/containers/RoutineSettings/RoutineSettings.d.ts +10 -0
  222. package/dist/types/src/containers/RoutineSettings/RoutineSettings.d.ts.map +1 -0
  223. package/dist/types/src/containers/RoutineSettings/index.d.ts +2 -0
  224. package/dist/types/src/containers/RoutineSettings/index.d.ts.map +1 -0
  225. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.d.ts +9 -0
  226. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.d.ts.map +1 -0
  227. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.d.ts +15 -0
  228. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.d.ts.map +1 -0
  229. package/dist/types/src/containers/RoutineTraceCompanion/index.d.ts +2 -0
  230. package/dist/types/src/containers/RoutineTraceCompanion/index.d.ts.map +1 -0
  231. package/dist/types/src/containers/RoutineTraceCompanion/runs.d.ts +34 -0
  232. package/dist/types/src/containers/RoutineTraceCompanion/runs.d.ts.map +1 -0
  233. package/dist/types/src/containers/RoutineTraceCompanion/runs.test.d.ts +2 -0
  234. package/dist/types/src/containers/RoutineTraceCompanion/runs.test.d.ts.map +1 -0
  235. package/dist/types/src/containers/RoutineTraceCompanion/useRoutineRuns.d.ts +11 -0
  236. package/dist/types/src/containers/RoutineTraceCompanion/useRoutineRuns.d.ts.map +1 -0
  237. package/dist/types/src/containers/SkillArticle/SkillArticle.d.ts +6 -0
  238. package/dist/types/src/containers/SkillArticle/SkillArticle.d.ts.map +1 -0
  239. package/dist/types/src/containers/SkillArticle/index.d.ts +2 -0
  240. package/dist/types/src/containers/SkillArticle/index.d.ts.map +1 -0
  241. package/dist/types/src/containers/index.d.ts +7 -0
  242. package/dist/types/src/containers/index.d.ts.map +1 -0
  243. package/dist/types/src/hooks/index.d.ts +2 -0
  244. package/dist/types/src/hooks/index.d.ts.map +1 -0
  245. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts +12 -0
  246. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts.map +1 -0
  247. package/dist/types/src/index.d.ts +4 -0
  248. package/dist/types/src/index.d.ts.map +1 -0
  249. package/dist/types/src/meta.d.ts +33 -0
  250. package/dist/types/src/meta.d.ts.map +1 -0
  251. package/dist/types/src/operations/create-routine.d.ts +5 -0
  252. package/dist/types/src/operations/create-routine.d.ts.map +1 -0
  253. package/dist/types/src/operations/create-trigger-from-template.d.ts +5 -0
  254. package/dist/types/src/operations/create-trigger-from-template.d.ts.map +1 -0
  255. package/dist/types/src/operations/index.d.ts +3 -0
  256. package/dist/types/src/operations/index.d.ts.map +1 -0
  257. package/dist/types/src/operations/run-routine.d.ts +5 -0
  258. package/dist/types/src/operations/run-routine.d.ts.map +1 -0
  259. package/dist/types/src/paths.d.ts +5 -0
  260. package/dist/types/src/paths.d.ts.map +1 -0
  261. package/dist/types/src/plugin.d.ts +4 -0
  262. package/dist/types/src/plugin.d.ts.map +1 -0
  263. package/dist/types/src/templates/index.d.ts +11 -0
  264. package/dist/types/src/templates/index.d.ts.map +1 -0
  265. package/dist/types/src/testing/index.d.ts +2 -0
  266. package/dist/types/src/testing/index.d.ts.map +1 -0
  267. package/dist/types/src/testing/test-functions.d.ts +328 -0
  268. package/dist/types/src/testing/test-functions.d.ts.map +1 -0
  269. package/dist/types/src/testing.d.ts +2 -0
  270. package/dist/types/src/testing.d.ts.map +1 -0
  271. package/dist/types/src/translations.d.ts +3 -0
  272. package/dist/types/src/translations.d.ts.map +1 -0
  273. package/dist/types/src/types/Routine.d.ts +55 -0
  274. package/dist/types/src/types/Routine.d.ts.map +1 -0
  275. package/dist/types/src/types/Routine.test.d.ts +2 -0
  276. package/dist/types/src/types/Routine.test.d.ts.map +1 -0
  277. package/dist/types/src/types/RoutineCapabilities.d.ts +44 -0
  278. package/dist/types/src/types/RoutineCapabilities.d.ts.map +1 -0
  279. package/dist/types/src/types/RoutineOperation.d.ts +45 -0
  280. package/dist/types/src/types/RoutineOperation.d.ts.map +1 -0
  281. package/dist/types/src/types/index.d.ts +5 -0
  282. package/dist/types/src/types/index.d.ts.map +1 -0
  283. package/dist/types/src/types/schema.d.ts +33 -0
  284. package/dist/types/src/types/schema.d.ts.map +1 -0
  285. package/dist/types/src/util/index.d.ts +3 -0
  286. package/dist/types/src/util/index.d.ts.map +1 -0
  287. package/dist/types/src/util/routines-for-object.d.ts +22 -0
  288. package/dist/types/src/util/routines-for-object.d.ts.map +1 -0
  289. package/dist/types/src/util/routines-for-object.test.d.ts +2 -0
  290. package/dist/types/src/util/routines-for-object.test.d.ts.map +1 -0
  291. package/dist/types/src/util/run-instructions.d.ts +5 -0
  292. package/dist/types/src/util/run-instructions.d.ts.map +1 -0
  293. package/dist/types/src/util/run-instructions.test.d.ts +2 -0
  294. package/dist/types/src/util/run-instructions.test.d.ts.map +1 -0
  295. package/dist/types/tsconfig.tsbuildinfo +1 -0
  296. package/dx.config.ts +33 -0
  297. package/package.json +196 -0
  298. package/src/RoutinePlugin.node.ts +48 -0
  299. package/src/RoutinePlugin.test.ts +27 -0
  300. package/src/RoutinePlugin.tsx +58 -0
  301. package/src/RoutinePlugin.workerd.ts +24 -0
  302. package/src/capabilities/app-graph-builder.ts +80 -0
  303. package/src/capabilities/create-object.test.ts +18 -0
  304. package/src/capabilities/create-object.ts +26 -0
  305. package/src/capabilities/index.ts +22 -0
  306. package/src/capabilities/layer-specs.ts +190 -0
  307. package/src/capabilities/navigation-resolver.ts +21 -0
  308. package/src/capabilities/node.ts +19 -0
  309. package/src/capabilities/operation-handler.ts +16 -0
  310. package/src/capabilities/react-surface.tsx +66 -0
  311. package/src/capabilities/registry-sync.ts +114 -0
  312. package/src/capabilities/templates.ts +17 -0
  313. package/src/capabilities/trigger-runtime-controller.test.ts +107 -0
  314. package/src/capabilities/trigger-runtime-controller.ts +126 -0
  315. package/src/commands/index.ts +5 -0
  316. package/src/commands/trigger/create/index.ts +14 -0
  317. package/src/commands/trigger/create/queue.ts +87 -0
  318. package/src/commands/trigger/create/subscription.ts +126 -0
  319. package/src/commands/trigger/create/timer.ts +90 -0
  320. package/src/commands/trigger/index.ts +16 -0
  321. package/src/commands/trigger/list.ts +69 -0
  322. package/src/commands/trigger/options.ts +47 -0
  323. package/src/commands/trigger/remove.ts +45 -0
  324. package/src/commands/trigger/update/index.ts +14 -0
  325. package/src/commands/trigger/update/queue.ts +191 -0
  326. package/src/commands/trigger/update/subscription.ts +278 -0
  327. package/src/commands/trigger/update/timer.ts +194 -0
  328. package/src/commands/trigger/util.ts +412 -0
  329. package/src/components/CreateRoutinePanel/CreateRoutinePanel.tsx +68 -0
  330. package/src/components/CreateRoutinePanel/index.ts +5 -0
  331. package/src/components/InstructionsEditor/InstructionsEditor.stories.tsx +69 -0
  332. package/src/components/InstructionsEditor/InstructionsEditor.tsx +107 -0
  333. package/src/components/InstructionsEditor/index.ts +5 -0
  334. package/src/components/MasterDetail/MasterDetail.stories.tsx +100 -0
  335. package/src/components/MasterDetail/MasterDetail.tsx +175 -0
  336. package/src/components/MasterDetail/index.ts +5 -0
  337. package/src/components/RoutineForm/RoutineForm.tsx +293 -0
  338. package/src/components/RoutineForm/index.ts +5 -0
  339. package/src/components/Schedule/Schedule.stories.tsx +73 -0
  340. package/src/components/Schedule/Schedule.tsx +527 -0
  341. package/src/components/Schedule/cron.test.ts +230 -0
  342. package/src/components/Schedule/cron.ts +337 -0
  343. package/src/components/Schedule/index.ts +8 -0
  344. package/src/components/Schedule/types.ts +124 -0
  345. package/src/components/TemplateEditor/TemplateEditor.stories.tsx +93 -0
  346. package/src/components/TemplateEditor/TemplateEditor.tsx +77 -0
  347. package/src/components/TemplateEditor/TemplateForm.stories.tsx +76 -0
  348. package/src/components/TemplateEditor/TemplateForm.tsx +204 -0
  349. package/src/components/TemplateEditor/extensions/handlebars-extension.ts +274 -0
  350. package/src/components/TemplateEditor/extensions/index.ts +6 -0
  351. package/src/components/TemplateEditor/extensions/xml-extension.ts +64 -0
  352. package/src/components/TemplateEditor/index.ts +5 -0
  353. package/src/components/TemplateEditor/types.tsx +28 -0
  354. package/src/components/TriggerEditor/TriggerEditor.stories.tsx +122 -0
  355. package/src/components/TriggerEditor/TriggerEditor.tsx +365 -0
  356. package/src/components/TriggerEditor/TriggerKindSelector.stories.tsx +42 -0
  357. package/src/components/TriggerEditor/TriggerKindSelector.tsx +87 -0
  358. package/src/components/TriggerEditor/index.ts +5 -0
  359. package/src/components/index.ts +11 -0
  360. package/src/containers/RoutineArticle/RoutineArticle.stories.tsx +146 -0
  361. package/src/containers/RoutineArticle/RoutineArticle.tsx +109 -0
  362. package/src/containers/RoutineArticle/index.ts +5 -0
  363. package/src/containers/RoutineCompanion/RoutineCompanion.stories.tsx +82 -0
  364. package/src/containers/RoutineCompanion/RoutineCompanion.tsx +342 -0
  365. package/src/containers/RoutineCompanion/index.ts +6 -0
  366. package/src/containers/RoutineSettings/RoutineSettings.tsx +65 -0
  367. package/src/containers/RoutineSettings/index.ts +5 -0
  368. package/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.tsx +133 -0
  369. package/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.tsx +125 -0
  370. package/src/containers/RoutineTraceCompanion/index.ts +5 -0
  371. package/src/containers/RoutineTraceCompanion/runs.test.ts +140 -0
  372. package/src/containers/RoutineTraceCompanion/runs.ts +135 -0
  373. package/src/containers/RoutineTraceCompanion/useRoutineRuns.ts +50 -0
  374. package/src/containers/SkillArticle/SkillArticle.tsx +29 -0
  375. package/src/containers/SkillArticle/index.ts +5 -0
  376. package/src/containers/index.ts +11 -0
  377. package/src/hooks/index.ts +6 -0
  378. package/src/hooks/useTriggerRuntimeControls.ts +70 -0
  379. package/src/index.ts +7 -0
  380. package/src/meta.ts +9 -0
  381. package/src/operations/create-routine.ts +39 -0
  382. package/src/operations/create-trigger-from-template.ts +68 -0
  383. package/src/operations/index.ts +11 -0
  384. package/src/operations/run-routine.ts +45 -0
  385. package/src/paths.ts +18 -0
  386. package/src/plugin.ts +11 -0
  387. package/src/templates/index.ts +48 -0
  388. package/src/testing/index.ts +5 -0
  389. package/src/testing/test-functions.ts +76 -0
  390. package/src/testing.ts +7 -0
  391. package/src/translations.ts +125 -0
  392. package/src/types/Routine.test.ts +51 -0
  393. package/src/types/Routine.ts +144 -0
  394. package/src/types/RoutineCapabilities.ts +51 -0
  395. package/src/types/RoutineOperation.ts +104 -0
  396. package/src/types/index.ts +9 -0
  397. package/src/types/schema.ts +31 -0
  398. package/src/util/index.ts +6 -0
  399. package/src/util/routines-for-object.test.ts +109 -0
  400. package/src/util/routines-for-object.ts +89 -0
  401. package/src/util/run-instructions.test.ts +23 -0
  402. package/src/util/run-instructions.ts +12 -0
  403. package/src/vite-env.d.ts +10 -0
@@ -0,0 +1,100 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Atom } from '@effect-atom/atom-react';
6
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
7
+ import * as Schema from 'effect/Schema';
8
+ import React, { useState } from 'react';
9
+
10
+ import { Panel, ScrollArea } from '@dxos/react-ui';
11
+ import { Form } from '@dxos/react-ui-form';
12
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
13
+
14
+ import { translations } from '#translations';
15
+
16
+ import { MasterDetail, type MasterDetailIcon } from './MasterDetail';
17
+
18
+ type Row = { id: string; label: string };
19
+
20
+ const ROWS: Row[] = [
21
+ { id: '1', label: 'Daily digest' },
22
+ { id: '2', label: 'Sync inbox' },
23
+ { id: '3', label: 'Weekly report' },
24
+ ];
25
+
26
+ const DetailSchema = Schema.Struct({
27
+ name: Schema.String.annotations({ title: 'Name' }),
28
+ description: Schema.optional(Schema.String).annotations({ title: 'Description' }),
29
+ });
30
+
31
+ // Mirrors RoutineForm's gutter (Form.Viewport owns a `Column.Root` gutter); used to check list/detail alignment.
32
+ const MockDetail = ({ row }: { row: Row }) => (
33
+ <Form.Root schema={DetailSchema} values={{ name: row.label, description: '' }}>
34
+ <Form.Viewport>
35
+ <Form.Content>
36
+ <Form.FieldSet />
37
+ </Form.Content>
38
+ </Form.Viewport>
39
+ </Form.Root>
40
+ );
41
+
42
+ const getIcon = (_get: Atom.Context): MasterDetailIcon => ({ icon: 'ph--lightning--regular' });
43
+
44
+ const DefaultStory = () => {
45
+ const [selectedId, setSelectedId] = useState<string | undefined>('1');
46
+ const selected = ROWS.find((row) => row.id === selectedId);
47
+
48
+ return (
49
+ <Panel.Root>
50
+ <Panel.Content asChild className='pt-trim-md'>
51
+ <ScrollArea.Root orientation='vertical'>
52
+ <ScrollArea.Viewport>
53
+ <MasterDetail<Row>
54
+ classNames='dx-document'
55
+ items={ROWS}
56
+ selectedId={selectedId}
57
+ onSelect={setSelectedId}
58
+ getLabel={(_get, row) => row.label}
59
+ getIcon={getIcon}
60
+ detail={selected ? <MockDetail row={selected} /> : null}
61
+ emptyLabel='No items'
62
+ />
63
+ </ScrollArea.Viewport>
64
+ </ScrollArea.Root>
65
+ </Panel.Content>
66
+ </Panel.Root>
67
+ );
68
+ };
69
+
70
+ const meta = {
71
+ title: 'plugins/plugin-routine/components/MasterDetail',
72
+ render: DefaultStory,
73
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
74
+ parameters: { layout: 'fullscreen', translations },
75
+ } satisfies Meta<typeof DefaultStory>;
76
+
77
+ export default meta;
78
+
79
+ type Story = StoryObj<typeof meta>;
80
+
81
+ export const Default: Story = {};
82
+
83
+ export const Empty: Story = {
84
+ render: () => (
85
+ <Panel.Root>
86
+ <Panel.Content asChild className='pt-trim-md'>
87
+ <ScrollArea.Root orientation='vertical'>
88
+ <ScrollArea.Viewport>
89
+ <MasterDetail<Row>
90
+ classNames='dx-document'
91
+ items={[]}
92
+ getLabel={(_get, row) => row.label}
93
+ emptyLabel='No items'
94
+ />
95
+ </ScrollArea.Viewport>
96
+ </ScrollArea.Root>
97
+ </Panel.Content>
98
+ </Panel.Root>
99
+ ),
100
+ };
@@ -0,0 +1,175 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Atom, useAtomValue } from '@effect-atom/atom-react';
6
+ import React, { type ReactNode, useMemo } from 'react';
7
+
8
+ import { Column, Icon, IconBlock, IconButton, type ThemedClassName, Tooltip, useTranslation } from '@dxos/react-ui';
9
+ import { Empty, OrderedList } from '@dxos/react-ui-list';
10
+ import { type ActionGraphProps, Menu, useMenuBuilder } from '@dxos/react-ui-menu';
11
+ import { getStyles } from '@dxos/ui-theme';
12
+
13
+ import { meta } from '#meta';
14
+
15
+ // Prototype master-detail layout, candidate to push down into @dxos/react-ui-list as a reusable
16
+ // component. Presentation-only: a selectable list (master) on top of a single detail pane, with an
17
+ // optional empty state. The parent owns the detail content (the selected item's form, a draft form,
18
+ // etc.) and the selection state.
19
+
20
+ export type MasterDetailRecord = { id: string };
21
+
22
+ /** A row's leading icon: same shape as {@link Obj.getIcon} — a Phosphor icon name and an optional hue. */
23
+ export type MasterDetailIcon = { icon: string; hue?: string };
24
+
25
+ /** A row's trailing adornment: a status icon with a tooltip label (e.g. a 'detached' warning badge). */
26
+ export type MasterDetailAdornment = { icon: string; label: string };
27
+
28
+ const EMPTY_MENU: ActionGraphProps = { nodes: [], edges: [] };
29
+
30
+ export type MasterDetailProps<T extends MasterDetailRecord> = ThemedClassName<{
31
+ items: readonly T[];
32
+ /** Currently highlighted row; `undefined` clears the selection (e.g. while a draft is active). */
33
+ selectedId?: string;
34
+ onSelect?: (id: string | undefined) => void;
35
+ /**
36
+ * Build the row's label reactively. Run inside an atom so it can subscribe to the item's state via `get`
37
+ * (e.g. the object's name) and update live when it changes.
38
+ */
39
+ getLabel: (get: Atom.Context, item: T) => string;
40
+ /**
41
+ * Build the row's leading icon reactively. Run inside an atom so it can subscribe to the item's state via
42
+ * `get` (e.g. colour the icon by an `enabled` flag); returns the icon name and optional colour classes.
43
+ */
44
+ getIcon?: (get: Atom.Context, item: T) => MasterDetailIcon | undefined;
45
+ /**
46
+ * Build the row's trailing adornment reactively (e.g. a status badge). Run inside an atom so it can subscribe
47
+ * to the item's state via `get`; returns a Phosphor icon name and a tooltip label, or `undefined` for none.
48
+ */
49
+ getAdornment?: (get: Atom.Context, item: T) => MasterDetailAdornment | undefined;
50
+ /**
51
+ * Build the per-row overflow (three-dots) menu. Run inside each row's `useMenuBuilder`, so it should
52
+ * subscribe to that item's reactive state via `get` (e.g. an `enabled` flag) — the menu then updates live
53
+ * without re-rendering the whole list.
54
+ */
55
+ getMenu?: (get: Atom.Context, item: T) => ActionGraphProps;
56
+ /** Message shown when there are no items. */
57
+ emptyLabel?: string;
58
+ /** Detail pane content (selected item's form, draft form, …); rendered below the list. */
59
+ detail?: ReactNode;
60
+ }>;
61
+
62
+ /** Selectable master list (with an optional per-row overflow menu) above a parent-supplied detail pane. */
63
+ export const MasterDetail = <T extends MasterDetailRecord>({
64
+ classNames,
65
+ items,
66
+ selectedId,
67
+ onSelect,
68
+ getLabel,
69
+ getIcon,
70
+ getAdornment,
71
+ getMenu,
72
+ emptyLabel,
73
+ detail,
74
+ }: MasterDetailProps<T>) => {
75
+ // The gutter is owned by a `Column.Root` (not an ad-hoc wrapper) so the list aligns to the surface's
76
+ // column system: rows and their selection highlight sit in the centre track (`Column.Center`), matching
77
+ // the inset of the detail's form. The detail bleeds the full width since its own `Form` owns its gutter.
78
+ return (
79
+ <Column.Root gutter='sm' classNames={classNames}>
80
+ <Column.Center>
81
+ {(items.length === 0 && <Empty label={emptyLabel} />) || (
82
+ <OrderedList.Root<T> items={items}>
83
+ {({ items }) => (
84
+ <OrderedList.Content>
85
+ {items.map((item) => (
86
+ <MasterDetailRow
87
+ key={item.id}
88
+ item={item}
89
+ selected={item.id === selectedId}
90
+ getLabel={getLabel}
91
+ getIcon={getIcon}
92
+ getAdornment={getAdornment}
93
+ getMenu={getMenu}
94
+ onSelect={onSelect}
95
+ />
96
+ ))}
97
+ </OrderedList.Content>
98
+ )}
99
+ </OrderedList.Root>
100
+ )}
101
+ </Column.Center>
102
+
103
+ <div className='col-span-full pt-trim-md'>{detail}</div>
104
+ </Column.Root>
105
+ );
106
+ };
107
+
108
+ type MasterDetailRowProps<T extends MasterDetailRecord> = {
109
+ item: T;
110
+ selected: boolean;
111
+ getLabel: (get: Atom.Context, item: T) => string;
112
+ getIcon?: (get: Atom.Context, item: T) => MasterDetailIcon | undefined;
113
+ getAdornment?: (get: Atom.Context, item: T) => MasterDetailAdornment | undefined;
114
+ getMenu?: (get: Atom.Context, item: T) => ActionGraphProps;
115
+ onSelect?: (id: string | undefined) => void;
116
+ };
117
+
118
+ const MasterDetailRow = <T extends MasterDetailRecord>({
119
+ item,
120
+ selected,
121
+ getLabel,
122
+ getIcon,
123
+ getAdornment,
124
+ getMenu,
125
+ onSelect,
126
+ }: MasterDetailRowProps<T>) => {
127
+ const { t } = useTranslation(meta.profile.key);
128
+ // Resolve the label, icon, adornment, and actions reactively per row — each subscribes (via `get`) only to
129
+ // this item's state, so a change (rename, toggling enabled) updates just this row.
130
+ const label = useAtomValue(useMemo(() => Atom.make((get) => getLabel(get, item)), [getLabel, item]));
131
+ const icon = useAtomValue(useMemo(() => Atom.make((get) => getIcon?.(get, item)), [getIcon, item]));
132
+ const adornment = useAtomValue(useMemo(() => Atom.make((get) => getAdornment?.(get, item)), [getAdornment, item]));
133
+ const menu = useMenuBuilder((get) => getMenu?.(get, item) ?? EMPTY_MENU, [getMenu, item]);
134
+
135
+ return (
136
+ <OrderedList.Item
137
+ id={item.id}
138
+ item={item}
139
+ canDrag={false}
140
+ hover
141
+ selected={selected}
142
+ classNames='flex items-center cursor-pointer p-1'
143
+ onClick={() => onSelect?.(selected ? undefined : item.id)}
144
+ >
145
+ {icon && (
146
+ <IconBlock>
147
+ <Icon icon={icon.icon} classNames={icon.hue ? getStyles(icon.hue).text : undefined} />
148
+ </IconBlock>
149
+ )}
150
+ <span className='grow truncate'>{label}</span>
151
+ {adornment && (
152
+ <Tooltip.Provider>
153
+ <Tooltip.Trigger asChild side='bottom' content={adornment.label}>
154
+ <Icon icon={adornment.icon} />
155
+ </Tooltip.Trigger>
156
+ </Tooltip.Provider>
157
+ )}
158
+ {getMenu && (
159
+ <Menu.Root {...menu}>
160
+ <Menu.Trigger asChild>
161
+ <IconButton
162
+ iconOnly
163
+ variant='ghost'
164
+ icon='ph--dots-three-vertical--regular'
165
+ label={t('routine-actions.label')}
166
+ // Open the menu without toggling row selection.
167
+ onClick={(event) => event.stopPropagation()}
168
+ />
169
+ </Menu.Trigger>
170
+ <Menu.Content />
171
+ </Menu.Root>
172
+ )}
173
+ </OrderedList.Item>
174
+ );
175
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export * from './MasterDetail';
@@ -0,0 +1,293 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import React, { type PropsWithChildren, useCallback, useMemo } from 'react';
7
+
8
+ import { Instructions, Operation, Trigger } from '@dxos/compute';
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';
12
+ import { Form, type FormFieldMap, RefField } from '@dxos/react-ui-form';
13
+
14
+ import { meta } from '#meta';
15
+ import { Routine } from '#types';
16
+
17
+ import { InstructionsEditor } from '../InstructionsEditor';
18
+ import { TriggerEditor } from '../TriggerEditor';
19
+
20
+ //
21
+ // Main (general) form — the outer form; actions and triggers are sub-forms within its content.
22
+ //
23
+
24
+ // Pick the editable general fields from the Routine schema rather than redeclaring them.
25
+ const GeneralForm = Type.getSchema(Routine.Routine).pipe(Schema.pick('name', 'description'));
26
+ type GeneralForm = Schema.Schema.Type<typeof GeneralForm>;
27
+
28
+ export type RoutineFormProps = {
29
+ db: Database.Database;
30
+ routine: Routine.Routine;
31
+ /** Render the form for display only (e.g. an enabled routine, locked until disabled). */
32
+ readonly?: boolean;
33
+ /** Commit the edit session; when set, the form renders a Save/Cancel action row (the companion's create flow). */
34
+ onSave?: () => void;
35
+ /** Discard the edit session. */
36
+ onCancel?: () => void;
37
+ };
38
+
39
+ /**
40
+ * Composite routine form: the general fields (name + description) are the outer {@link Form},
41
+ * with the Actions and Triggers sections rendered as sub-forms inside its content:
42
+ * - Actions — Operation/Instructions variants chosen via a button group (single action; `spec` isn't an array).
43
+ * - Triggers — the {@link TriggerEditor}.
44
+ *
45
+ * The sub-forms read and autosave the routine's owned instructions and primary trigger directly off the
46
+ * `routine` graph (live editing); `readonly` displays them without edit affordances. The optional Save/Cancel
47
+ * row is used only by the companion's create-from-template flow.
48
+ */
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);
53
+
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
+ );
68
+
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 />
81
+
82
+ <Section title={t('actions.title')}>
83
+ <ActionEditor db={db} routine={routine} readonly={readonly} />
84
+ </Section>
85
+
86
+ <Section title={t('triggers.title')}>
87
+ <TriggerEditor db={db} routine={routine} trigger={trigger} readonly={readonly} />
88
+ </Section>
89
+
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
+ };
97
+
98
+ /** Lightweight labelled grouping for a sub-form (no `Settings` chrome). */
99
+ const Section = ({ title, children }: PropsWithChildren<{ title: string }>) => (
100
+ <div role='none' className='flex flex-col mbs-4'>
101
+ <Form.Label standalone label={title} />
102
+ {children}
103
+ </div>
104
+ );
105
+
106
+ //
107
+ // Actions
108
+ //
109
+
110
+ /**
111
+ * Single action: an Operation (the routine's `spec.runnable`) or an owned Instructions edited inline. The
112
+ * action kind is derived from the routine's `spec` — an absent spec means "operation, none chosen yet" (a
113
+ * 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.
115
+ */
116
+ const ActionEditor = ({
117
+ db,
118
+ routine: routineProp,
119
+ readonly,
120
+ }: {
121
+ db: Database.Database;
122
+ routine: Routine.Routine;
123
+ readonly?: boolean;
124
+ }) => {
125
+ const operations = useOperations(db);
126
+ const [routine, updateRoutine] = useObject(routineProp);
127
+
128
+ // Classification is read off `spec.kind` (no dereference); the owned instructions object is then resolved in
129
+ // place to hand to the editor (an owned ref is always locally resolvable, and the parent `useObject` re-renders
130
+ // this when `spec` changes). An absent spec means "runnable, none chosen yet" — a scaffolded routine always
131
+ // carries an instructions spec, so the only way to clear it is switching to a runnable action.
132
+ const kind = routine.spec?.kind ?? 'runnable';
133
+ const operationRef = Routine.runnableRef(routine);
134
+ const instructions = Routine.instructionsRef(routine)?.target;
135
+
136
+ const handleOperationChange = useCallback(
137
+ (operation?: Ref.Ref<Operation.PersistentOperation>) => {
138
+ updateRoutine((routine) => {
139
+ routine.spec = operation ? { kind: 'runnable', runnable: operation } : undefined;
140
+ });
141
+ // Keep the owned trigger's `function`/`input` in sync with the new action.
142
+ Routine.wireTriggers(routineProp);
143
+ },
144
+ [updateRoutine, routineProp],
145
+ );
146
+
147
+ const handleKindChange = useCallback(
148
+ (next: Routine.Kind) => {
149
+ updateRoutine((routine) => {
150
+ if (next === 'runnable') {
151
+ // Switch to an operation action; the operation is chosen via the picker below. A previously-owned
152
+ // instructions stays parented to the routine (cascade-deleted with it) but is no longer the action.
153
+ routine.spec = undefined;
154
+ } else if (routine.spec?.kind !== 'instructions') {
155
+ // Seed an owned instructions action (the executing operation is the implicit RunInstructions).
156
+ const instructions = Instructions.make({});
157
+ Obj.setParent(instructions, routine);
158
+ routine.spec = { kind: 'instructions', instructions: Ref.make(instructions) };
159
+ }
160
+ });
161
+ // Re-wire the owned trigger to dispatch the new action (RunInstructions vs the operation).
162
+ Routine.wireTriggers(routineProp);
163
+ },
164
+ [updateRoutine, routineProp],
165
+ );
166
+
167
+ return (
168
+ <div role='none' className='flex flex-col'>
169
+ {!readonly && <ActionKindToggle value={kind} onChange={handleKindChange} />}
170
+ {kind === 'runnable' ? (
171
+ <OperationEditor
172
+ db={db}
173
+ operations={operations}
174
+ operation={operationRef}
175
+ onChange={handleOperationChange}
176
+ readonly={readonly}
177
+ />
178
+ ) : instructions ? (
179
+ <InstructionsEditor db={db} instructions={instructions} readonly={readonly} />
180
+ ) : null}
181
+ </div>
182
+ );
183
+ };
184
+
185
+ const ActionKindToggle = ({ value, onChange }: { value: Routine.Kind; onChange: (kind: Routine.Kind) => void }) => {
186
+ const { t } = useTranslation(meta.profile.key);
187
+ return (
188
+ // `type='single'` emits `''` when the selected item is clicked again (toggled off); ignore that and any
189
+ // other non-kind value so it can't fall through and overwrite the current action.
190
+ <ToggleGroup
191
+ type='single'
192
+ value={value}
193
+ onValueChange={(next) => {
194
+ if (next === 'instructions' || next === 'runnable') {
195
+ onChange(next);
196
+ }
197
+ }}
198
+ >
199
+ <ToggleGroupItem value='instructions'>{t('action-kind.instructions.label')}</ToggleGroupItem>
200
+ <ToggleGroupItem value='runnable'>{t('action-kind.operation.label')}</ToggleGroupItem>
201
+ </ToggleGroup>
202
+ );
203
+ };
204
+
205
+ const OperationActionForm = Schema.Struct({
206
+ operation: Ref.Ref(Operation.PersistentOperation).pipe(Schema.annotations({ title: 'Operation' }), Schema.optional),
207
+ });
208
+ type OperationActionValues = Schema.Schema.Type<typeof OperationActionForm>;
209
+
210
+ // Operation picker options: surface each operation's registry key (plugin/id) as the option's secondary
211
+ // line and sort by name. The `id` derivation mirrors the RefField default so a selected operation ref
212
+ // still matches its option.
213
+ const getOperationOptions = (results: Entity.Any[]): { id: string; label: string; description?: string }[] =>
214
+ results
215
+ // Hide internal operations: only operations annotated visible are user-bindable as trigger actions.
216
+ .filter((operation) => !Obj.instanceOf(Operation.PersistentOperation, operation) || Operation.isVisible(operation))
217
+ .map((operation) => {
218
+ const id = Entity.getURI(operation, { prefer: 'named' });
219
+ const name = Entity.getLabel(operation) ?? id;
220
+ const key = Obj.instanceOf(Operation.PersistentOperation, operation) ? Operation.getKey(operation) : undefined;
221
+ return { id, label: name, description: key };
222
+ })
223
+ .sort((left, right) => left.label.localeCompare(right.label));
224
+
225
+ /** Sub-form: ref picker for an Operation. Draws options from the queried operation set (space + registry). */
226
+ const OperationEditor = ({
227
+ db,
228
+ operations,
229
+ operation,
230
+ onChange,
231
+ readonly,
232
+ }: {
233
+ db: Database.Database;
234
+ operations: ReturnType<typeof useOperations>;
235
+ operation?: Ref.Ref<Operation.PersistentOperation>;
236
+ onChange?: (operation?: Ref.Ref<Operation.PersistentOperation>) => void;
237
+ readonly?: boolean;
238
+ }) => {
239
+ const fieldMap = useMemo<FormFieldMap>(
240
+ () => ({
241
+ operation: (props) => (
242
+ <RefField {...props} db={db} useResults={() => operations} getOptions={getOperationOptions} />
243
+ ),
244
+ }),
245
+ [db, operations],
246
+ );
247
+ const defaultValues = useMemo<Partial<OperationActionValues>>(() => ({ operation }), [operation]);
248
+ const handleValuesChanged = useCallback(
249
+ (values: Partial<OperationActionValues>) => onChange?.(values.operation),
250
+ [onChange],
251
+ );
252
+
253
+ return (
254
+ <Form.Root
255
+ schema={OperationActionForm}
256
+ db={db}
257
+ readonly={readonly}
258
+ defaultValues={defaultValues}
259
+ fieldMap={fieldMap}
260
+ onValuesChanged={handleValuesChanged}
261
+ >
262
+ <Form.FieldSet />
263
+ </Form.Root>
264
+ );
265
+ };
266
+
267
+ //
268
+ // Hooks
269
+ //
270
+
271
+ /** Operations available to bind as an action (space-resident plus registry / plugin-provided). */
272
+ const useOperations = (db: Database.Database) =>
273
+ useQuery(
274
+ db,
275
+ Query.select(Filter.type(DXN.make(Type.getTypename(Operation.PersistentOperation)))).from(
276
+ Scope.space(),
277
+ Scope.registry(),
278
+ ),
279
+ );
280
+
281
+ /** Subscribe to the routine and derive its primary (first) trigger. */
282
+ const usePrimaryTrigger = (routine: Routine.Routine): Trigger.Trigger | undefined => {
283
+ const [snapshot] = useObject(routine);
284
+ return useMemo(() => {
285
+ for (const ref of snapshot.triggers) {
286
+ const target = ref.target;
287
+ if (Obj.instanceOf(Trigger.Trigger, target)) {
288
+ return target;
289
+ }
290
+ }
291
+ return undefined;
292
+ }, [snapshot.triggers]);
293
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export * from './RoutineForm';
@@ -0,0 +1,73 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { useState } from 'react';
7
+
8
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
9
+
10
+ import { translations } from '#translations';
11
+
12
+ import { Schedule, type ScheduleValue } from './Schedule';
13
+
14
+ const DefaultStory = ({ initial, minInterval }: { initial: ScheduleValue; minInterval?: number }) => {
15
+ const [value, setValue] = useState<ScheduleValue>(initial);
16
+
17
+ return (
18
+ <div className='p-4 flex flex-col gap-3'>
19
+ <Schedule.Root
20
+ classNames='bg-card-surface border border-separator rounded-sm p-2'
21
+ timezone='EDT'
22
+ minInterval={minInterval}
23
+ value={value}
24
+ onValueChange={setValue}
25
+ >
26
+ <Schedule.Header />
27
+ <Schedule.Kind />
28
+ <Schedule.Body />
29
+ </Schedule.Root>
30
+ <div className='flex flex-col gap-1'>
31
+ <p className='text-xs text-subdued'>Value</p>
32
+ <pre className='font-mono text-sm bg-base-surface rounded p-2 whitespace-pre-wrap'>
33
+ {JSON.stringify(value, null, 2)}
34
+ </pre>
35
+ </div>
36
+ </div>
37
+ );
38
+ };
39
+
40
+ const meta = {
41
+ title: 'plugins/plugin-routine/components/Schedule',
42
+ render: DefaultStory,
43
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
44
+ parameters: {
45
+ layout: 'fullscreen',
46
+ translations,
47
+ },
48
+ } satisfies Meta<typeof DefaultStory>;
49
+
50
+ export default meta;
51
+
52
+ type Story = StoryObj<typeof meta>;
53
+
54
+ export const Weekly: Story = {
55
+ args: { initial: { kind: 'weekly', time: '09:00', days: ['mon'] } },
56
+ };
57
+
58
+ export const Hourly: Story = {
59
+ args: { initial: { kind: 'hourly', minute: 0 } },
60
+ };
61
+
62
+ export const Monthly: Story = {
63
+ args: { initial: { kind: 'monthly', day: 1, time: '09:00' } },
64
+ };
65
+
66
+ export const Custom: Story = {
67
+ args: { initial: { kind: 'custom', cron: '0 9 * * MON-FRI' } },
68
+ };
69
+
70
+ // A 5-minute minimum clamps a too-frequent custom cron (`* * * * *` -> `*/5 * * * *`).
71
+ export const MinInterval: Story = {
72
+ args: { initial: { kind: 'custom', cron: '* * * * *' }, minInterval: 300 },
73
+ };