@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,527 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import React, { type PropsWithChildren, createContext, forwardRef, useCallback, useContext, useState } from 'react';
6
+
7
+ import { invariant } from '@dxos/invariant';
8
+ import {
9
+ Input,
10
+ ThemedClassName,
11
+ ToggleGroup,
12
+ ToggleGroupItem,
13
+ composable,
14
+ composableProps,
15
+ useTranslation,
16
+ } from '@dxos/react-ui';
17
+ import { mx } from '@dxos/ui-theme';
18
+
19
+ import { meta } from '#meta';
20
+
21
+ import {
22
+ MAX_MIN_INTERVAL_SECONDS,
23
+ clampSchedule,
24
+ describeCron,
25
+ fromCron,
26
+ scheduleIntervalSeconds,
27
+ scheduleToCron,
28
+ } from './cron';
29
+
30
+ //
31
+ // Value model.
32
+ //
33
+
34
+ export const ScheduleKinds = [
35
+ // TODO(burdon): Once cannot be converted to a cron expression.
36
+ // 'once',
37
+ 'hourly',
38
+ 'daily',
39
+ 'weekly',
40
+ 'monthly',
41
+ 'custom',
42
+ ] as const;
43
+ export type ScheduleKind = (typeof ScheduleKinds)[number];
44
+
45
+ const isScheduleKind = (value: string): value is ScheduleKind => (ScheduleKinds as readonly string[]).includes(value);
46
+
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
+ /** Discriminated schedule value. Times are `HH:mm` (24h); `once.date` is `YYYY-MM-DDTHH:mm`. */
59
+ export type ScheduleValue =
60
+ // | { kind: 'once'; date?: string }
61
+ | { kind: 'hourly'; minute: number }
62
+ | { kind: 'daily'; time: string }
63
+ | { kind: 'weekly'; time: string; days: Day[] }
64
+ | { kind: 'monthly'; day: number; time: string }
65
+ | { kind: 'custom'; cron: string };
66
+
67
+ const DEFAULT_TIME = '08:00';
68
+
69
+ /** Default minimum interval: a schedule may fire at most once every 60s (the finest 5-field cron granularity). */
70
+ const DEFAULT_MIN_INTERVAL_SECONDS = 60;
71
+
72
+ /** Clamp a requested minimum interval to the achievable range; a 5-field cron cannot fire more often than every minute or require slower than hourly. */
73
+ const normalizeMinInterval = (minInterval: number): number => {
74
+ // Guard non-finite input (NaN/Infinity) so the clamp can't yield NaN and produce a `*/NaN` cron.
75
+ const finite = Number.isFinite(minInterval) ? minInterval : DEFAULT_MIN_INTERVAL_SECONDS;
76
+ return Math.min(MAX_MIN_INTERVAL_SECONDS, Math.max(DEFAULT_MIN_INTERVAL_SECONDS, Math.round(finite)));
77
+ };
78
+
79
+ const KIND_LABEL_KEYS: Record<ScheduleKind, string> = {
80
+ // once: 'schedule.kind.once.label',
81
+ hourly: 'schedule.kind.hourly.label',
82
+ daily: 'schedule.kind.daily.label',
83
+ weekly: 'schedule.kind.weekly.label',
84
+ monthly: 'schedule.kind.monthly.label',
85
+ custom: 'schedule.kind.custom.label',
86
+ };
87
+
88
+ const DEFAULTS: { [K in ScheduleKind]: Extract<ScheduleValue, { kind: K }> } = {
89
+ // once: {
90
+ // kind: 'once',
91
+ // },
92
+ hourly: {
93
+ kind: 'hourly',
94
+ minute: 0,
95
+ },
96
+ daily: {
97
+ kind: 'daily',
98
+ time: DEFAULT_TIME,
99
+ },
100
+ weekly: {
101
+ kind: 'weekly',
102
+ time: DEFAULT_TIME,
103
+ days: ['mon'],
104
+ },
105
+ monthly: {
106
+ kind: 'monthly',
107
+ day: 1,
108
+ time: DEFAULT_TIME,
109
+ },
110
+ custom: {
111
+ kind: 'custom',
112
+ cron: '0 9 * * 1',
113
+ },
114
+ };
115
+
116
+ const pad = (value: number): string => String(value).padStart(2, '0');
117
+
118
+ /**
119
+ * Switch to a different kind, preserving the current schedule's timing by routing it through its cron
120
+ * representation. The cron is the canonical carrier: each target kind reuses whatever fields it supports
121
+ * (time-of-day, weekdays, day-of-month), falling back to the kind's default for fields the cron doesn't hold.
122
+ */
123
+ const switchKind = (current: ScheduleValue, kind: ScheduleKind): ScheduleValue => {
124
+ const cron = scheduleToCron(current);
125
+ const spec = cron ? fromCron(cron) : undefined;
126
+ // Fall back to the shared default time (not midnight) when the source cron carries no time-of-day,
127
+ // so switching from e.g. hourly to daily lands on a sensible hour rather than 00:00.
128
+ const [defaultHour, defaultMinute] = DEFAULT_TIME.split(':').map(Number);
129
+ const minute = spec && 'minute' in spec ? spec.minute : defaultMinute;
130
+ const hour = spec && 'hour' in spec ? spec.hour : defaultHour;
131
+ const time = `${pad(hour)}:${pad(minute)}`;
132
+ switch (kind) {
133
+ case 'hourly':
134
+ return { kind: 'hourly', minute };
135
+ case 'daily':
136
+ return { kind: 'daily', time };
137
+ case 'weekly':
138
+ return { kind: 'weekly', time, days: spec?.frequency === 'weekly' ? [...spec.daysOfWeek] : DEFAULTS.weekly.days };
139
+ case 'monthly':
140
+ return { kind: 'monthly', time, day: spec?.frequency === 'monthly' ? spec.daysOfMonth[0] : DEFAULTS.monthly.day };
141
+ case 'custom':
142
+ return { kind: 'custom', cron: cron ?? DEFAULTS.custom.cron };
143
+ }
144
+ };
145
+
146
+ //
147
+ // Context
148
+ //
149
+
150
+ type ScheduleContextValue = {
151
+ value: ScheduleValue;
152
+ onValueChange: (value: ScheduleValue) => void;
153
+ kinds: readonly ScheduleKind[];
154
+ /** Minimum seconds between fires; schedules that would fire more often are clamped. */
155
+ minInterval: number;
156
+ timezone?: string;
157
+ };
158
+
159
+ const ScheduleContext = createContext<ScheduleContextValue | null>(null);
160
+
161
+ const useScheduleContext = (consumer: string): ScheduleContextValue => {
162
+ const context = useContext(ScheduleContext);
163
+ invariant(context, `${consumer} must be used within Schedule.Root`);
164
+ return context;
165
+ };
166
+
167
+ //
168
+ // Root
169
+ //
170
+
171
+ export type ScheduleRootProps = ThemedClassName<
172
+ PropsWithChildren<{
173
+ value?: ScheduleValue;
174
+ /** Timezone abbreviation shown in the summary, e.g. `EDT`. */
175
+ timezone?: string;
176
+ defaultValue?: ScheduleValue;
177
+ onValueChange?: (value: ScheduleValue) => void;
178
+ /** Restrict which frequency tabs are offered (defaults to all kinds). */
179
+ kinds?: readonly ScheduleKind[];
180
+ /**
181
+ * Minimum seconds between fires (default 60). Schedules that would fire more often are clamped, and
182
+ * frequency tabs that cannot satisfy it are hidden. Capped to the hourly cadence a 5-field cron can model.
183
+ */
184
+ minInterval?: number;
185
+ }>
186
+ >;
187
+
188
+ /**
189
+ * Schedule picker root: provides the shared {@link Column} grid (all rows align to the same gutters)
190
+ * and the schedule state context. Controllable via `value`/`onValueChange`, or self-managing via
191
+ * `defaultValue`. Compose with `Schedule.Header`, `Schedule.Kind`, `Schedule.Body`, `Schedule.Description`.
192
+ */
193
+ const ScheduleRoot = composable<HTMLDivElement, ScheduleRootProps>(
194
+ (
195
+ {
196
+ children,
197
+ value: valueProp,
198
+ defaultValue,
199
+ onValueChange,
200
+ kinds = ScheduleKinds,
201
+ minInterval: minIntervalProp = DEFAULT_MIN_INTERVAL_SECONDS,
202
+ timezone,
203
+ ...props
204
+ },
205
+ forwardedRef,
206
+ ) => {
207
+ const minInterval = normalizeMinInterval(minIntervalProp);
208
+ const [value, setValue] = useState<ScheduleValue>(() =>
209
+ clampSchedule(valueProp ?? defaultValue ?? DEFAULTS.weekly, minInterval),
210
+ );
211
+
212
+ const handleValueChange = useCallback(
213
+ (next: ScheduleValue) => {
214
+ const clamped = clampSchedule(next, minInterval);
215
+ setValue(clamped);
216
+ onValueChange?.(clamped);
217
+ },
218
+ [onValueChange, minInterval],
219
+ );
220
+
221
+ // Only offer frequencies whose cadence can satisfy the minimum; `custom` always stays (it is clamped on edit).
222
+ const allowedKinds = kinds.filter(
223
+ (kind) => kind === 'custom' || scheduleIntervalSeconds(DEFAULTS[kind]) >= minInterval,
224
+ );
225
+
226
+ return (
227
+ <ScheduleContext.Provider
228
+ value={{
229
+ value: clampSchedule(valueProp ?? value, minInterval),
230
+ onValueChange: handleValueChange,
231
+ kinds: allowedKinds,
232
+ minInterval,
233
+ timezone,
234
+ }}
235
+ >
236
+ <div {...composableProps(props, { classNames: 'flex flex-col gap-y-3' })} ref={forwardedRef}>
237
+ {children}
238
+ </div>
239
+ </ScheduleContext.Provider>
240
+ );
241
+ },
242
+ );
243
+
244
+ ScheduleRoot.displayName = 'Schedule.Root';
245
+
246
+ //
247
+ // Header
248
+ //
249
+
250
+ export type ScheduleHeaderProps = { classNames?: string };
251
+
252
+ /**
253
+ * Summary row laid out on the shared grid: the icon in the leading gutter (column 1), the schedule
254
+ * description (or `children`) in the center column, and an optional close button in the trailing gutter
255
+ * (column 3).
256
+ */
257
+ const ScheduleHeader = forwardRef<HTMLDivElement, ScheduleHeaderProps>(({ classNames }, forwardedRef) => {
258
+ const { t } = useTranslation(meta.profile.key);
259
+ const { value, timezone } = useScheduleContext('Schedule.Header');
260
+ return <p className={mx('grow truncate text-description', classNames)}>{describeSchedule(value, timezone)}</p>;
261
+ });
262
+
263
+ ScheduleHeader.displayName = 'Schedule.Header';
264
+
265
+ //
266
+ // Kind
267
+ //
268
+
269
+ export type ScheduleKindProps = ThemedClassName;
270
+
271
+ /** Segmented frequency tabs (Once / Hourly / Daily / Weekly / Custom). */
272
+ const ScheduleKindRow = forwardRef<HTMLDivElement, ScheduleKindProps>(({ classNames }, forwardedRef) => {
273
+ const { t } = useTranslation(meta.profile.key);
274
+ const { value, onValueChange, kinds } = useScheduleContext('Schedule.Kind');
275
+ const handleKindChange = useCallback(
276
+ (kind: string) => {
277
+ if (isScheduleKind(kind)) {
278
+ onValueChange(switchKind(value, kind));
279
+ }
280
+ },
281
+ [value, onValueChange],
282
+ );
283
+
284
+ return (
285
+ <ToggleGroup
286
+ classNames='overflow-x-auto scrollbar-none'
287
+ type='single'
288
+ value={value.kind}
289
+ onValueChange={handleKindChange}
290
+ >
291
+ {kinds.map((kind) => (
292
+ <ToggleGroupItem key={kind} value={kind}>
293
+ {t(KIND_LABEL_KEYS[kind])}
294
+ </ToggleGroupItem>
295
+ ))}
296
+ </ToggleGroup>
297
+ );
298
+ });
299
+
300
+ ScheduleKindRow.displayName = 'Schedule.Kind';
301
+
302
+ //
303
+ // Body
304
+ //
305
+
306
+ export type ScheduleBodyProps = ThemedClassName;
307
+
308
+ /** Per-kind editor for the active frequency. Rendered as a 3-column row so editors can use the gutters. */
309
+ const ScheduleBody = forwardRef<HTMLDivElement, ScheduleBodyProps>(({ classNames }, forwardedRef) => {
310
+ const { value, onValueChange } = useScheduleContext('Schedule.Body');
311
+ return <ScheduleEditor value={value} onChange={onValueChange} />;
312
+ });
313
+
314
+ ScheduleBody.displayName = 'Schedule.Body';
315
+
316
+ //
317
+ // Namespace.
318
+ //
319
+
320
+ export const Schedule = {
321
+ Root: ScheduleRoot,
322
+ Header: ScheduleHeader,
323
+ Kind: ScheduleKindRow,
324
+ Body: ScheduleBody,
325
+ };
326
+
327
+ //
328
+ // Per-kind editors.
329
+ //
330
+
331
+ const Field = ({ label, children, classNames }: ThemedClassName<PropsWithChildren<{ label: string }>>) => (
332
+ <label className={mx('flex items-center gap-2 shrink-0', classNames)}>
333
+ <span className='text-sm'>{label}</span>
334
+ {children}
335
+ </label>
336
+ );
337
+
338
+ const ScheduleEditor = ({ value, onChange }: { value: ScheduleValue; onChange: (value: ScheduleValue) => void }) => {
339
+ const { t } = useTranslation(meta.profile.key);
340
+ switch (value.kind) {
341
+ // case 'once':
342
+ // `Input.Root` renders no DOM, so the trigger (column 1) and the field (center) become direct children
343
+ // of `Schedule.Body`'s row while still sharing the input context that wires the picker to the field.
344
+ // return (
345
+ // <Input.Root>
346
+ // <div>
347
+ // <Field label={t('schedule.at.label')}>
348
+ // <Input.DateTime
349
+ // classNames='min-w-0 overflow-hidden'
350
+ // hourCycle={12}
351
+ // value={value.date ?? ''}
352
+ // onValueChange={(date) => onChange({ kind: 'once', date: date || undefined })}
353
+ // />
354
+ // <Input.TriggerIcon />
355
+ // </Field>
356
+ // </div>
357
+ // </Input.Root>
358
+ // );
359
+
360
+ case 'hourly':
361
+ return (
362
+ <Field label={t('schedule.minute.label')}>
363
+ <Input.Root>
364
+ <Input.TextInput
365
+ type='number'
366
+ min={0}
367
+ max={59}
368
+ step={1}
369
+ classNames='w-15'
370
+ value={String(value.minute)}
371
+ onChange={(event) => {
372
+ const minute = Math.min(59, Math.max(0, Math.round(Number(event.target.value) || 0)));
373
+ onChange({ kind: 'hourly', minute });
374
+ }}
375
+ />
376
+ </Input.Root>
377
+ </Field>
378
+ );
379
+
380
+ case 'daily':
381
+ return (
382
+ <Field label={t('schedule.at.label')}>
383
+ <Input.Root>
384
+ <Input.Time hourCycle={12} value={value.time} onValueChange={(time) => onChange({ kind: 'daily', time })} />
385
+ </Input.Root>
386
+ </Field>
387
+ );
388
+
389
+ case 'weekly':
390
+ return (
391
+ <div className='@container dx-inline-size-container min-w-0 flex justify-between items-center gap-2 overflow-x-auto scrollbar-none'>
392
+ <Field label={t('schedule.at.label')}>
393
+ <Input.Root>
394
+ <Input.Time hourCycle={12} value={value.time} onValueChange={(time) => onChange({ ...value, time })} />
395
+ </Input.Root>
396
+ </Field>
397
+ <div className='flex shrink-0 items-center gap-2'>
398
+ <span className='shrink-0 text-sm'>{t('schedule.on.label')}</span>
399
+ <div className='grid w-max shrink-0 grid-cols-7 gap-x-2'>
400
+ {Days.map(({ value: day, label }) => {
401
+ const checked = value.days.includes(day);
402
+ return (
403
+ <div key={day} className='flex shrink-0 items-center gap-1'>
404
+ <Input.Root>
405
+ <Input.Checkbox
406
+ checked={checked}
407
+ onCheckedChange={(next) => {
408
+ // Preserve the canonical `Days` order so the summary reads naturally.
409
+ const nextDays = next
410
+ ? Days.map((d) => d.value).filter((d) => d === day || value.days.includes(d))
411
+ : value.days.filter((d) => d !== day);
412
+ // A weekly schedule must keep at least one day; an empty set serializes to `*`
413
+ // (every day), silently broadening execution. Ignore the uncheck in that case.
414
+ onChange({ ...value, days: nextDays.length > 0 ? nextDays : value.days });
415
+ }}
416
+ />
417
+ <Input.Label classNames='hidden @min-[32rem]:inline-block text-xs uppercase'>{label}</Input.Label>
418
+ <Input.Label classNames='inline-block @min-[32rem]:hidden text-xs'>{label.charAt(0)}</Input.Label>
419
+ </Input.Root>
420
+ </div>
421
+ );
422
+ })}
423
+ </div>
424
+ </div>
425
+ </div>
426
+ );
427
+
428
+ case 'monthly':
429
+ return (
430
+ <div className='flex items-center gap-3'>
431
+ <Field label={t('schedule.day.label')}>
432
+ <Input.Root>
433
+ <Input.TextInput
434
+ type='number'
435
+ min={1}
436
+ max={31}
437
+ step={1}
438
+ classNames='w-15'
439
+ value={String(value.day)}
440
+ onChange={(event) => {
441
+ const day = Math.min(31, Math.max(1, Math.round(Number(event.target.value) || 1)));
442
+ onChange({ ...value, day });
443
+ }}
444
+ />
445
+ </Input.Root>
446
+ </Field>
447
+ <Field label={t('schedule.at.label')}>
448
+ <Input.Root>
449
+ <Input.Time hourCycle={12} value={value.time} onValueChange={(time) => onChange({ ...value, time })} />
450
+ </Input.Root>
451
+ </Field>
452
+ </div>
453
+ );
454
+
455
+ case 'custom':
456
+ return (
457
+ <Field label={t('schedule.cron.label')}>
458
+ <Input.Root>
459
+ <Input.TextInput
460
+ classNames='w-50 tabular-nums'
461
+ placeholder='0 9 * * MON-FRI'
462
+ value={value.cron}
463
+ onChange={(event) => onChange({ kind: 'custom', cron: event.target.value })}
464
+ />
465
+ </Input.Root>
466
+ </Field>
467
+ );
468
+ }
469
+ };
470
+
471
+ //
472
+ // Summary.
473
+ //
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
+ };