@dxos/plugin-routine 0.9.1-staging.ee54ba693a → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/PLUGIN.mdl +18 -13
  2. package/dist/lib/RoutinePlugin.mjs +2 -0
  3. package/dist/lib/RoutinePlugin.node.mjs +894 -0
  4. package/dist/lib/RoutinePlugin.node.mjs.map +1 -0
  5. package/dist/lib/RoutinePlugin.workerd.mjs +20 -0
  6. package/dist/lib/RoutinePlugin.workerd.mjs.map +1 -0
  7. package/dist/lib/capabilities/node.mjs +12 -0
  8. package/dist/lib/capabilities/node.mjs.map +1 -0
  9. package/dist/lib/capabilities.mjs +14 -0
  10. package/dist/lib/capabilities.mjs.map +1 -0
  11. package/dist/lib/chunk-RoutineArticle.mjs +79 -0
  12. package/dist/lib/chunk-RoutineArticle.mjs.map +1 -0
  13. package/dist/lib/chunk-RoutineCompanion.mjs +192 -0
  14. package/dist/lib/chunk-RoutineCompanion.mjs.map +1 -0
  15. package/dist/lib/chunk-RoutinePlugin.mjs +38 -0
  16. package/dist/lib/chunk-RoutinePlugin.mjs.map +1 -0
  17. package/dist/lib/chunk-RoutineSettings.mjs +50 -0
  18. package/dist/lib/chunk-RoutineSettings.mjs.map +1 -0
  19. package/dist/lib/chunk-RoutineTraceCompanion.mjs +208 -0
  20. package/dist/lib/chunk-RoutineTraceCompanion.mjs.map +1 -0
  21. package/dist/lib/chunk-SkillArticle.mjs +28 -0
  22. package/dist/lib/chunk-SkillArticle.mjs.map +1 -0
  23. package/dist/lib/chunk-app-graph-builder.mjs +71 -0
  24. package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
  25. package/dist/lib/chunk-create-object.mjs +23 -0
  26. package/dist/lib/chunk-create-object.mjs.map +1 -0
  27. package/dist/lib/chunk-create-routine.mjs +34 -0
  28. package/dist/lib/chunk-create-routine.mjs.map +1 -0
  29. package/dist/lib/chunk-create-trigger-from-template.mjs +48 -0
  30. package/dist/lib/chunk-create-trigger-from-template.mjs.map +1 -0
  31. package/dist/lib/chunk-layer-specs.mjs +179 -0
  32. package/dist/lib/chunk-layer-specs.mjs.map +1 -0
  33. package/dist/lib/{neutral/chunk-HLO4LYXT.mjs → chunk-meta.mjs} +19 -27
  34. package/dist/lib/chunk-meta.mjs.map +1 -0
  35. package/dist/lib/chunk-operation-handler.mjs +11 -0
  36. package/dist/lib/chunk-operation-handler.mjs.map +1 -0
  37. package/dist/lib/chunk-paths.mjs +11 -0
  38. package/dist/lib/chunk-paths.mjs.map +1 -0
  39. package/dist/lib/chunk-react-surface.mjs +64 -0
  40. package/dist/lib/chunk-react-surface.mjs.map +1 -0
  41. package/dist/lib/chunk-registry-sync.mjs +104 -0
  42. package/dist/lib/chunk-registry-sync.mjs.map +1 -0
  43. package/dist/lib/chunk-run-routine.mjs +57 -0
  44. package/dist/lib/chunk-run-routine.mjs.map +1 -0
  45. package/dist/lib/chunk-templates.mjs +37 -0
  46. package/dist/lib/chunk-templates.mjs.map +1 -0
  47. package/dist/lib/chunk-trigger-runtime-controller.mjs +73 -0
  48. package/dist/lib/chunk-trigger-runtime-controller.mjs.map +1 -0
  49. package/dist/lib/chunk-types.mjs +149 -0
  50. package/dist/lib/chunk-types.mjs.map +1 -0
  51. package/dist/lib/chunk-util.mjs +142 -0
  52. package/dist/lib/chunk-util.mjs.map +1 -0
  53. package/dist/lib/components.mjs +1645 -0
  54. package/dist/lib/components.mjs.map +1 -0
  55. package/dist/lib/containers.mjs +11 -0
  56. package/dist/lib/containers.mjs.map +1 -0
  57. package/dist/lib/hooks.mjs +37 -0
  58. package/dist/lib/hooks.mjs.map +1 -0
  59. package/dist/lib/index.mjs +5 -0
  60. package/dist/lib/meta.mjs +2 -0
  61. package/dist/lib/operations.mjs +7 -0
  62. package/dist/lib/operations.mjs.map +1 -0
  63. package/dist/lib/plugin.mjs +9 -0
  64. package/dist/lib/plugin.mjs.map +1 -0
  65. package/dist/lib/testing.mjs +2 -0
  66. package/dist/lib/translations.mjs +110 -0
  67. package/dist/lib/translations.mjs.map +1 -0
  68. package/dist/lib/types.mjs +2 -0
  69. package/dist/types/src/RoutinePlugin.d.ts.map +1 -1
  70. package/dist/types/src/RoutinePlugin.node.d.ts.map +1 -1
  71. package/dist/types/src/RoutinePlugin.workerd.d.ts.map +1 -1
  72. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  73. package/dist/types/src/capabilities/create-object.d.ts +1 -1
  74. package/dist/types/src/capabilities/index.d.ts +0 -1
  75. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  76. package/dist/types/src/capabilities/layer-specs.d.ts +1 -1
  77. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  78. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  79. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  80. package/dist/types/src/capabilities/registry-sync.d.ts +1 -1
  81. package/dist/types/src/capabilities/templates.d.ts +1 -1
  82. package/dist/types/src/capabilities/trigger-runtime-controller.d.ts +1 -1
  83. package/dist/types/src/commands/trigger/create/{queue.d.ts → feed.d.ts} +2 -2
  84. package/dist/types/src/commands/trigger/create/feed.d.ts.map +1 -0
  85. package/dist/types/src/commands/trigger/update/{queue.d.ts → feed.d.ts} +2 -2
  86. package/dist/types/src/commands/trigger/update/feed.d.ts.map +1 -0
  87. package/dist/types/src/commands/trigger/util.d.ts +1 -1
  88. package/dist/types/src/commands/trigger/util.d.ts.map +1 -1
  89. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.d.ts +7 -5
  90. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.d.ts.map +1 -1
  91. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.stories.d.ts +3 -3
  92. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.stories.d.ts.map +1 -1
  93. package/dist/types/src/components/RoutineCard/RoutineCard.d.ts +9 -0
  94. package/dist/types/src/components/RoutineCard/RoutineCard.d.ts.map +1 -0
  95. package/dist/types/src/components/RoutineCard/RoutineCard.stories.d.ts +21 -0
  96. package/dist/types/src/components/RoutineCard/RoutineCard.stories.d.ts.map +1 -0
  97. package/dist/types/src/components/RoutineCard/index.d.ts +2 -0
  98. package/dist/types/src/components/RoutineCard/index.d.ts.map +1 -0
  99. package/dist/types/src/components/RoutineForm/RoutineForm.d.ts +7 -2
  100. package/dist/types/src/components/RoutineForm/RoutineForm.d.ts.map +1 -1
  101. package/dist/types/src/components/Schedule/Schedule.d.ts +2 -26
  102. package/dist/types/src/components/Schedule/Schedule.d.ts.map +1 -1
  103. package/dist/types/src/components/Schedule/days.d.ts +24 -0
  104. package/dist/types/src/components/Schedule/days.d.ts.map +1 -0
  105. package/dist/types/src/components/Schedule/describe-schedule.d.ts +3 -0
  106. package/dist/types/src/components/Schedule/describe-schedule.d.ts.map +1 -0
  107. package/dist/types/src/components/Schedule/index.d.ts +2 -0
  108. package/dist/types/src/components/Schedule/index.d.ts.map +1 -1
  109. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts +1 -1
  110. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts.map +1 -1
  111. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +1 -2
  112. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
  113. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.d.ts +5 -2
  114. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.d.ts.map +1 -1
  115. package/dist/types/src/components/TriggerEditor/trigger-kind-icon.d.ts +5 -0
  116. package/dist/types/src/components/TriggerEditor/trigger-kind-icon.d.ts.map +1 -0
  117. package/dist/types/src/components/index.d.ts +1 -1
  118. package/dist/types/src/components/index.d.ts.map +1 -1
  119. package/dist/types/src/containers/RoutineArticle/RoutineArticle.d.ts +5 -10
  120. package/dist/types/src/containers/RoutineArticle/RoutineArticle.d.ts.map +1 -1
  121. package/dist/types/src/containers/RoutineArticle/RoutineArticle.stories.d.ts +6 -2
  122. package/dist/types/src/containers/RoutineArticle/RoutineArticle.stories.d.ts.map +1 -1
  123. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.d.ts +4 -12
  124. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.d.ts.map +1 -1
  125. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.stories.d.ts.map +1 -1
  126. package/dist/types/src/containers/RoutineSettings/RoutineSettings.d.ts +4 -8
  127. package/dist/types/src/containers/RoutineSettings/RoutineSettings.d.ts.map +1 -1
  128. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.d.ts +5 -3
  129. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.d.ts.map +1 -1
  130. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.d.ts.map +1 -1
  131. package/dist/types/src/containers/RoutineTraceCompanion/useRoutineRuns.d.ts +1 -1
  132. package/dist/types/src/containers/RoutineTraceCompanion/useRoutineRuns.d.ts.map +1 -1
  133. package/dist/types/src/containers/SkillArticle/SkillArticle.d.ts +4 -1
  134. package/dist/types/src/containers/SkillArticle/SkillArticle.d.ts.map +1 -1
  135. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts +1 -1
  136. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts.map +1 -1
  137. package/dist/types/src/index.d.ts +1 -0
  138. package/dist/types/src/index.d.ts.map +1 -1
  139. package/dist/types/src/operations/run-routine.d.ts.map +1 -1
  140. package/dist/types/src/operations/run-routine.test.d.ts +2 -0
  141. package/dist/types/src/operations/run-routine.test.d.ts.map +1 -0
  142. package/dist/types/src/paths.d.ts.map +1 -1
  143. package/dist/types/src/templates/index.d.ts +1 -1
  144. package/dist/types/src/templates/index.d.ts.map +1 -1
  145. package/dist/types/src/testing/test-functions.d.ts +30 -6
  146. package/dist/types/src/testing/test-functions.d.ts.map +1 -1
  147. package/dist/types/src/translations.d.ts.map +1 -1
  148. package/dist/types/src/types/RoutineCapabilities.d.ts +9 -3
  149. package/dist/types/src/types/RoutineCapabilities.d.ts.map +1 -1
  150. package/dist/types/src/types/RoutineOperation.d.ts +2 -3
  151. package/dist/types/src/types/RoutineOperation.d.ts.map +1 -1
  152. package/dist/types/src/types/index.d.ts +0 -1
  153. package/dist/types/src/types/index.d.ts.map +1 -1
  154. package/dist/types/src/util/index.d.ts +1 -0
  155. package/dist/types/src/util/index.d.ts.map +1 -1
  156. package/dist/types/src/util/routines-for-object.d.ts +6 -3
  157. package/dist/types/src/util/routines-for-object.d.ts.map +1 -1
  158. package/dist/types/src/util/wire.d.ts +21 -0
  159. package/dist/types/src/util/wire.d.ts.map +1 -0
  160. package/dist/types/src/util/wire.test.d.ts +2 -0
  161. package/dist/types/src/util/wire.test.d.ts.map +1 -0
  162. package/dist/types/tsconfig.tsbuildinfo +1 -1
  163. package/dx.config.ts +3 -2
  164. package/package.json +73 -71
  165. package/src/RoutinePlugin.node.ts +1 -2
  166. package/src/RoutinePlugin.tsx +2 -4
  167. package/src/RoutinePlugin.workerd.ts +1 -2
  168. package/src/capabilities/app-graph-builder.ts +9 -7
  169. package/src/capabilities/create-object.ts +2 -2
  170. package/src/capabilities/index.ts +0 -1
  171. package/src/capabilities/layer-specs.ts +78 -12
  172. package/src/capabilities/{react-surface.tsx → react-surface.ts} +18 -22
  173. package/src/capabilities/trigger-runtime-controller.test.ts +12 -18
  174. package/src/capabilities/trigger-runtime-controller.ts +22 -25
  175. package/src/commands/trigger/create/{queue.ts → feed.ts} +1 -1
  176. package/src/commands/trigger/create/index.ts +2 -2
  177. package/src/commands/trigger/update/{queue.ts → feed.ts} +1 -1
  178. package/src/commands/trigger/update/index.ts +2 -2
  179. package/src/commands/trigger/util.ts +1 -2
  180. package/src/components/InstructionsEditor/InstructionsEditor.stories.tsx +7 -6
  181. package/src/components/InstructionsEditor/InstructionsEditor.tsx +31 -19
  182. package/src/components/RoutineCard/RoutineCard.stories.tsx +95 -0
  183. package/src/components/RoutineCard/RoutineCard.tsx +60 -0
  184. package/src/components/{MasterDetail → RoutineCard}/index.ts +1 -1
  185. package/src/components/RoutineForm/RoutineForm.tsx +60 -52
  186. package/src/components/Schedule/Schedule.stories.tsx +1 -1
  187. package/src/components/Schedule/Schedule.tsx +4 -73
  188. package/src/components/Schedule/days.ts +18 -0
  189. package/src/components/Schedule/describe-schedule.ts +64 -0
  190. package/src/components/Schedule/index.ts +2 -0
  191. package/src/components/TemplateEditor/TemplateEditor.stories.tsx +1 -1
  192. package/src/components/TemplateEditor/TemplateForm.tsx +1 -1
  193. package/src/components/TriggerEditor/TriggerEditor.stories.tsx +3 -3
  194. package/src/components/TriggerEditor/TriggerEditor.tsx +79 -66
  195. package/src/components/TriggerEditor/TriggerKindSelector.tsx +4 -30
  196. package/src/components/TriggerEditor/trigger-kind-icon.ts +38 -0
  197. package/src/components/index.ts +1 -1
  198. package/src/containers/RoutineArticle/RoutineArticle.stories.tsx +78 -19
  199. package/src/containers/RoutineArticle/RoutineArticle.tsx +8 -4
  200. package/src/containers/RoutineCompanion/RoutineCompanion.stories.tsx +5 -4
  201. package/src/containers/RoutineCompanion/RoutineCompanion.tsx +11 -7
  202. package/src/containers/RoutineSettings/RoutineSettings.tsx +22 -33
  203. package/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.tsx +6 -5
  204. package/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.tsx +3 -1
  205. package/src/containers/RoutineTraceCompanion/useRoutineRuns.ts +3 -5
  206. package/src/containers/SkillArticle/SkillArticle.tsx +2 -0
  207. package/src/hooks/useTriggerRuntimeControls.ts +2 -2
  208. package/src/index.ts +1 -0
  209. package/src/operations/create-routine.ts +1 -1
  210. package/src/operations/create-trigger-from-template.ts +2 -2
  211. package/src/operations/run-routine.test.ts +150 -0
  212. package/src/operations/run-routine.ts +18 -2
  213. package/src/paths.ts +5 -5
  214. package/src/templates/index.ts +5 -3
  215. package/src/translations.ts +5 -6
  216. package/src/types/RoutineCapabilities.ts +10 -4
  217. package/src/types/RoutineOperation.ts +7 -6
  218. package/src/types/index.ts +0 -1
  219. package/src/util/index.ts +1 -0
  220. package/src/util/routines-for-object.test.ts +37 -5
  221. package/src/util/routines-for-object.ts +33 -8
  222. package/src/util/wire.test.ts +77 -0
  223. package/src/util/wire.ts +76 -0
  224. package/dist/lib/neutral/RoutineArticle-UNTMV4CC.mjs +0 -95
  225. package/dist/lib/neutral/RoutineArticle-UNTMV4CC.mjs.map +0 -7
  226. package/dist/lib/neutral/RoutineCompanion-ZZ6WMY7I.mjs +0 -249
  227. package/dist/lib/neutral/RoutineCompanion-ZZ6WMY7I.mjs.map +0 -7
  228. package/dist/lib/neutral/RoutinePlugin.mjs +0 -10
  229. package/dist/lib/neutral/RoutinePlugin.mjs.map +0 -7
  230. package/dist/lib/neutral/RoutinePlugin.node.mjs +0 -1133
  231. package/dist/lib/neutral/RoutinePlugin.node.mjs.map +0 -7
  232. package/dist/lib/neutral/RoutinePlugin.workerd.mjs +0 -36
  233. package/dist/lib/neutral/RoutinePlugin.workerd.mjs.map +0 -7
  234. package/dist/lib/neutral/RoutineSettings-ZJOM4F3S.mjs +0 -48
  235. package/dist/lib/neutral/RoutineSettings-ZJOM4F3S.mjs.map +0 -7
  236. package/dist/lib/neutral/RoutineTraceCompanion-5U6R7LJE.mjs +0 -236
  237. package/dist/lib/neutral/RoutineTraceCompanion-5U6R7LJE.mjs.map +0 -7
  238. package/dist/lib/neutral/SkillArticle-WWDNKW2Z.mjs +0 -27
  239. package/dist/lib/neutral/SkillArticle-WWDNKW2Z.mjs.map +0 -7
  240. package/dist/lib/neutral/app-graph-builder-FALWLZTI.mjs +0 -90
  241. package/dist/lib/neutral/app-graph-builder-FALWLZTI.mjs.map +0 -7
  242. package/dist/lib/neutral/capabilities/index.mjs +0 -25
  243. package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
  244. package/dist/lib/neutral/capabilities/node.mjs +0 -19
  245. package/dist/lib/neutral/capabilities/node.mjs.map +0 -7
  246. package/dist/lib/neutral/chunk-674LDIUJ.mjs +0 -9
  247. package/dist/lib/neutral/chunk-674LDIUJ.mjs.map +0 -7
  248. package/dist/lib/neutral/chunk-HLO4LYXT.mjs.map +0 -7
  249. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  250. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  251. package/dist/lib/neutral/chunk-P3TDQKOO.mjs +0 -8
  252. package/dist/lib/neutral/chunk-P3TDQKOO.mjs.map +0 -7
  253. package/dist/lib/neutral/chunk-R7J2MU2M.mjs +0 -263
  254. package/dist/lib/neutral/chunk-R7J2MU2M.mjs.map +0 -7
  255. package/dist/lib/neutral/chunk-WLNL77C7.mjs +0 -14
  256. package/dist/lib/neutral/chunk-WLNL77C7.mjs.map +0 -7
  257. package/dist/lib/neutral/chunk-YGWSAKLD.mjs +0 -65
  258. package/dist/lib/neutral/chunk-YGWSAKLD.mjs.map +0 -7
  259. package/dist/lib/neutral/components/index.mjs +0 -1921
  260. package/dist/lib/neutral/components/index.mjs.map +0 -7
  261. package/dist/lib/neutral/containers/index.mjs +0 -17
  262. package/dist/lib/neutral/containers/index.mjs.map +0 -7
  263. package/dist/lib/neutral/create-object-V23KVDMJ.mjs +0 -25
  264. package/dist/lib/neutral/create-object-V23KVDMJ.mjs.map +0 -7
  265. package/dist/lib/neutral/create-routine-6QBY6TWF.mjs +0 -38
  266. package/dist/lib/neutral/create-routine-6QBY6TWF.mjs.map +0 -7
  267. package/dist/lib/neutral/create-trigger-from-template-U3KNS77V.mjs +0 -70
  268. package/dist/lib/neutral/create-trigger-from-template-U3KNS77V.mjs.map +0 -7
  269. package/dist/lib/neutral/hooks/index.mjs +0 -47
  270. package/dist/lib/neutral/hooks/index.mjs.map +0 -7
  271. package/dist/lib/neutral/index.mjs +0 -27
  272. package/dist/lib/neutral/index.mjs.map +0 -7
  273. package/dist/lib/neutral/layer-specs-2TWJU5HI.mjs +0 -135
  274. package/dist/lib/neutral/layer-specs-2TWJU5HI.mjs.map +0 -7
  275. package/dist/lib/neutral/meta.json +0 -1
  276. package/dist/lib/neutral/meta.mjs +0 -8
  277. package/dist/lib/neutral/meta.mjs.map +0 -7
  278. package/dist/lib/neutral/navigation-resolver-KQIWUH6F.mjs +0 -18
  279. package/dist/lib/neutral/navigation-resolver-KQIWUH6F.mjs.map +0 -7
  280. package/dist/lib/neutral/operation-handler-QKLJSDCQ.mjs +0 -13
  281. package/dist/lib/neutral/operation-handler-QKLJSDCQ.mjs.map +0 -7
  282. package/dist/lib/neutral/operations/index.mjs +0 -8
  283. package/dist/lib/neutral/operations/index.mjs.map +0 -7
  284. package/dist/lib/neutral/plugin.mjs +0 -16
  285. package/dist/lib/neutral/plugin.mjs.map +0 -7
  286. package/dist/lib/neutral/react-surface-GMO7I7YE.mjs +0 -67
  287. package/dist/lib/neutral/react-surface-GMO7I7YE.mjs.map +0 -7
  288. package/dist/lib/neutral/registry-sync-DYPOC7ZG.mjs +0 -86
  289. package/dist/lib/neutral/registry-sync-DYPOC7ZG.mjs.map +0 -7
  290. package/dist/lib/neutral/run-routine-AEWO6SYD.mjs +0 -37
  291. package/dist/lib/neutral/run-routine-AEWO6SYD.mjs.map +0 -7
  292. package/dist/lib/neutral/templates-IIUCEBAX.mjs +0 -49
  293. package/dist/lib/neutral/templates-IIUCEBAX.mjs.map +0 -7
  294. package/dist/lib/neutral/testing.mjs +0 -8
  295. package/dist/lib/neutral/testing.mjs.map +0 -7
  296. package/dist/lib/neutral/translations.mjs +0 -115
  297. package/dist/lib/neutral/translations.mjs.map +0 -7
  298. package/dist/lib/neutral/trigger-runtime-controller-WIDDFGQT.mjs +0 -77
  299. package/dist/lib/neutral/trigger-runtime-controller-WIDDFGQT.mjs.map +0 -7
  300. package/dist/lib/neutral/types/index.mjs +0 -17
  301. package/dist/lib/neutral/types/index.mjs.map +0 -7
  302. package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -5
  303. package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
  304. package/dist/types/src/commands/trigger/create/queue.d.ts.map +0 -1
  305. package/dist/types/src/commands/trigger/update/queue.d.ts.map +0 -1
  306. package/dist/types/src/components/MasterDetail/MasterDetail.d.ts +0 -51
  307. package/dist/types/src/components/MasterDetail/MasterDetail.d.ts.map +0 -1
  308. package/dist/types/src/components/MasterDetail/MasterDetail.stories.d.ts +0 -16
  309. package/dist/types/src/components/MasterDetail/MasterDetail.stories.d.ts.map +0 -1
  310. package/dist/types/src/components/MasterDetail/index.d.ts +0 -2
  311. package/dist/types/src/components/MasterDetail/index.d.ts.map +0 -1
  312. package/dist/types/src/types/Routine.d.ts +0 -55
  313. package/dist/types/src/types/Routine.d.ts.map +0 -1
  314. package/dist/types/src/types/Routine.test.d.ts +0 -2
  315. package/dist/types/src/types/Routine.test.d.ts.map +0 -1
  316. package/src/capabilities/navigation-resolver.ts +0 -21
  317. package/src/components/MasterDetail/MasterDetail.stories.tsx +0 -100
  318. package/src/components/MasterDetail/MasterDetail.tsx +0 -175
  319. package/src/types/Routine.test.ts +0 -51
  320. package/src/types/Routine.ts +0 -144
@@ -0,0 +1,1645 @@
1
+ import { n as wireTriggers } from "./chunk-util.mjs";
2
+ import { isNonNullable } from "@dxos/util";
3
+ import { Instructions, Operation, Routine, Skill, Trigger } from "@dxos/compute";
4
+ import { meta } from "#meta";
5
+ import * as Schema from "effect/Schema";
6
+ import { DXN, Entity, Feed, Filter, Obj, Query, Ref, Scope, Type } from "@dxos/echo";
7
+ import * as Option from "effect/Option";
8
+ import { ParentLabelAnnotation } from "@dxos/schema";
9
+ import { createContext, forwardRef, useCallback, useContext, useMemo, useState } from "react";
10
+ import { useObject, useQuery } from "@dxos/echo-react";
11
+ import { Card, Icon, IconButton, Input, ToggleGroup, ToggleGroupItem, composable, composableProps, useThemeContext, useTranslation } from "@dxos/react-ui";
12
+ import { Form, RefField, SelectField } from "@dxos/react-ui-form";
13
+ import { HiddenAnnotation } from "@dxos/echo/Annotation";
14
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
+ import { mx } from "@dxos/ui-theme";
16
+ import cronstrue from "cronstrue";
17
+ import { invariant } from "@dxos/invariant";
18
+ import { Listbox } from "@dxos/react-ui-list";
19
+ import { useCapabilities } from "@dxos/app-framework/ui";
20
+ import { SearchList, useSearchListResults } from "@dxos/react-ui-search";
21
+ import { RoutineCapabilities } from "#types";
22
+ import { defaultHighlightStyle, syntaxHighlighting, syntaxTree } from "@codemirror/language";
23
+ import { composeRefs } from "@radix-ui/react-compose-refs";
24
+ import { Doc } from "@dxos/echo-doc";
25
+ import { useTextEditor } from "@dxos/react-ui-editor";
26
+ import { createBasicExtensions, createDataExtensions, createMarkdownExtensions, createThemeExtensions, decorateMarkdown } from "@dxos/ui-editor";
27
+ import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
28
+ import { RangeSetBuilder } from "@codemirror/state";
29
+ import { Decoration, ViewPlugin, WidgetType, keymap } from "@codemirror/view";
30
+ import { Domino, mx as mx$1 } from "@dxos/ui";
31
+ //#region src/components/InstructionsEditor/InstructionsEditor.tsx
32
+ var INSTRUCTIONS_SCHEMA = Type.getSchema(Instructions.Instructions);
33
+ var DEFAULT_FIELDS = ["text", "skills"];
34
+ /**
35
+ * Sub-form: edits the owned Instructions in place — by default its `text` (Markdown) and `skills`,
36
+ * both fields of the Instructions schema. A bare Form.Root + FieldSet (no Viewport) keeps these
37
+ * fields left-aligned with the sibling general/action forms; only the rendered fields are written
38
+ * back so a partial editor never clobbers the rest of the object.
39
+ */
40
+ var InstructionsEditor = ({ db: dbProp, instructions, readonly, fields = DEFAULT_FIELDS }) => {
41
+ const db = dbProp ?? Obj.getDatabase(instructions);
42
+ const defaultValues = useMemo(() => ({ ...Obj.getSnapshot(instructions) }), [instructions]);
43
+ const fieldSet = useMemo(() => new Set(fields), [fields]);
44
+ const handleValuesChanged = useCallback((values, { isValid }) => {
45
+ if (!isValid) return;
46
+ Obj.update(instructions, (instructions) => {
47
+ if (fieldSet.has("text") && values.text) instructions.text = values.text;
48
+ if (fieldSet.has("skills")) instructions.skills = [...values.skills ?? []];
49
+ if (fieldSet.has("objects")) instructions.objects = [...values.objects ?? []];
50
+ });
51
+ }, [instructions, fieldSet]);
52
+ return /* @__PURE__ */ jsx(Form.Root, {
53
+ schema: INSTRUCTIONS_SCHEMA,
54
+ db,
55
+ readonly,
56
+ defaultValues,
57
+ getOptions: getRefOptions,
58
+ onValuesChanged: handleValuesChanged,
59
+ children: /* @__PURE__ */ jsx(Form.FieldSet, { filter: (props) => props.filter((prop) => fieldSet.has(prop.name.toString())) })
60
+ }, instructions.id);
61
+ };
62
+ var isSystemObject = (object) => {
63
+ if (!Obj.isObject(object)) return false;
64
+ const typeEntity = Obj.getType(object);
65
+ if (!typeEntity) return false;
66
+ return HiddenAnnotation.get(Type.getSchema(typeEntity)).pipe(Option.getOrElse(() => false));
67
+ };
68
+ var getRefOptions = (results, { getTypePlaceholder } = {}) => results.filter((entity) => !isSystemObject(entity)).map((entity) => {
69
+ const id = Entity.getURI(entity, { prefer: "named" });
70
+ const typename = Entity.getTypename(entity);
71
+ return {
72
+ id,
73
+ label: Entity.getLabel(entity) ?? (typename ? getTypePlaceholder?.(typename) : void 0) ?? id,
74
+ description: Obj.instanceOf(Skill.Skill, entity) ? Obj.getMeta(entity).key : typename
75
+ };
76
+ }).sort((left, right) => left.label.localeCompare(right.label));
77
+ //#endregion
78
+ //#region src/components/Schedule/cron.ts
79
+ var DOW_MAP = {
80
+ sun: 0,
81
+ mon: 1,
82
+ tue: 2,
83
+ wed: 3,
84
+ thu: 4,
85
+ fri: 5,
86
+ sat: 6
87
+ };
88
+ /**
89
+ * Derives a 5-field standard cron expression from a decomposed CronSpec value.
90
+ * Fields: minute hour day-of-month month day-of-week
91
+ */
92
+ var toCron = (value) => {
93
+ switch (value.frequency) {
94
+ case "minutely": return `*/${value.interval} * * * *`;
95
+ case "hourly": return `${value.minute} */${value.interval} * * *`;
96
+ case "daily": return `${value.minute} ${value.hour} * * *`;
97
+ case "weekly": {
98
+ const dow = value.daysOfWeek.length > 0 ? value.daysOfWeek.map((d) => DOW_MAP[d]).join(",") : "*";
99
+ return `${value.minute} ${value.hour} * * ${dow}`;
100
+ }
101
+ case "monthly": {
102
+ const dom = value.daysOfMonth.length > 0 ? value.daysOfMonth.join(",") : "*";
103
+ return `${value.minute} ${value.hour} ${dom} * *`;
104
+ }
105
+ case "custom": return value.cronExpression || "* * * * *";
106
+ }
107
+ };
108
+ var DOW_REVERSE = {
109
+ "0": "sun",
110
+ "1": "mon",
111
+ "2": "tue",
112
+ "3": "wed",
113
+ "4": "thu",
114
+ "5": "fri",
115
+ "6": "sat",
116
+ "7": "sun"
117
+ };
118
+ /** Returns a non-negative integer if the token is a valid decimal integer, otherwise undefined. */
119
+ var parseUInt = (token) => /^\d+$/.test(token) ? Number(token) : void 0;
120
+ /** Returns the parsed integer if it falls within [min, max], otherwise undefined. */
121
+ var parseBoundedUInt = (token, min, max) => {
122
+ const value = parseUInt(token);
123
+ return value !== void 0 && value >= min && value <= max ? value : void 0;
124
+ };
125
+ /**
126
+ * Parses a 5-field cron expression into a CronSpec value.
127
+ * Recognises common patterns (minutely, hourly, daily, weekly, monthly) and falls back to `custom`.
128
+ */
129
+ var fromCron = (cron) => {
130
+ const parts = cron.trim().split(/\s+/);
131
+ if (parts.length !== 5) return {
132
+ frequency: "custom",
133
+ cronExpression: cron
134
+ };
135
+ const [minute, hour, dom, month, dow] = parts;
136
+ const minutelyMatch = minute.match(/^\*\/(\d+)$/);
137
+ if (minutelyMatch && hour === "*" && dom === "*" && month === "*" && dow === "*") return {
138
+ frequency: "minutely",
139
+ interval: parseInt(minutelyMatch[1])
140
+ };
141
+ const hourlyMatch = hour.match(/^\*\/(\d+)$/);
142
+ const minuteNum = parseBoundedUInt(minute, 0, 59);
143
+ if (hourlyMatch && dom === "*" && month === "*" && dow === "*" && minuteNum !== void 0) return {
144
+ frequency: "hourly",
145
+ interval: parseInt(hourlyMatch[1]),
146
+ minute: minuteNum
147
+ };
148
+ const hourNum = parseBoundedUInt(hour, 0, 23);
149
+ if (minuteNum === void 0 || hourNum === void 0) return {
150
+ frequency: "custom",
151
+ cronExpression: cron
152
+ };
153
+ if (dom === "*" && month === "*" && dow !== "*") {
154
+ const tokens = dow.split(",");
155
+ const days = tokens.map((d) => DOW_REVERSE[d]).filter((d) => d != null);
156
+ if (days.length === tokens.length && days.length > 0) return {
157
+ frequency: "weekly",
158
+ daysOfWeek: days,
159
+ hour: hourNum,
160
+ minute: minuteNum
161
+ };
162
+ return {
163
+ frequency: "custom",
164
+ cronExpression: cron
165
+ };
166
+ }
167
+ if (dom !== "*" && month === "*" && dow === "*") {
168
+ const tokens = dom.split(",");
169
+ const days = tokens.map((d) => parseBoundedUInt(d, 1, 31)).filter((d) => d !== void 0);
170
+ if (days.length === tokens.length && days.length > 0) return {
171
+ frequency: "monthly",
172
+ daysOfMonth: days,
173
+ hour: hourNum,
174
+ minute: minuteNum
175
+ };
176
+ return {
177
+ frequency: "custom",
178
+ cronExpression: cron
179
+ };
180
+ }
181
+ if (dom === "*" && month === "*" && dow === "*") return {
182
+ frequency: "daily",
183
+ hour: hourNum,
184
+ minute: minuteNum
185
+ };
186
+ return {
187
+ frequency: "custom",
188
+ cronExpression: cron
189
+ };
190
+ };
191
+ /**
192
+ * Returns a human-readable description of a cron expression, e.g. "At 09:00 on Monday".
193
+ * Falls back to the raw expression string on parse errors.
194
+ */
195
+ var describeCron = (cron) => {
196
+ try {
197
+ return cronstrue.toString(cron, { throwExceptionOnParseError: true });
198
+ } catch {
199
+ return cron;
200
+ }
201
+ };
202
+ var pad$1 = (value) => String(value).padStart(2, "0");
203
+ var splitTime = (time) => {
204
+ const [hour, minute] = time.split(":").map(Number);
205
+ return {
206
+ hour: Number.isFinite(hour) ? hour : 0,
207
+ minute: Number.isFinite(minute) ? minute : 0
208
+ };
209
+ };
210
+ var joinTime = (hour, minute) => `${pad$1(hour)}:${pad$1(minute)}`;
211
+ /**
212
+ * Convert a recurring {@link ScheduleValue} to a 5-field cron expression. The one-time `once` kind has no
213
+ * cron representation and returns `undefined`.
214
+ */
215
+ var scheduleToCron = (value) => {
216
+ switch (value.kind) {
217
+ case "hourly": return toCron({
218
+ frequency: "hourly",
219
+ interval: 1,
220
+ minute: value.minute
221
+ });
222
+ case "daily": {
223
+ const { hour, minute } = splitTime(value.time);
224
+ return toCron({
225
+ frequency: "daily",
226
+ hour,
227
+ minute
228
+ });
229
+ }
230
+ case "weekly": {
231
+ const { hour, minute } = splitTime(value.time);
232
+ return toCron({
233
+ frequency: "weekly",
234
+ daysOfWeek: value.days,
235
+ hour,
236
+ minute
237
+ });
238
+ }
239
+ case "monthly": {
240
+ const { hour, minute } = splitTime(value.time);
241
+ return toCron({
242
+ frequency: "monthly",
243
+ daysOfMonth: [value.day],
244
+ hour,
245
+ minute
246
+ });
247
+ }
248
+ case "custom": return toCron({
249
+ frequency: "custom",
250
+ cronExpression: value.cron
251
+ });
252
+ }
253
+ };
254
+ var MINUTE_SECONDS = 60;
255
+ var HOUR_SECONDS = 3600;
256
+ var DAY_SECONDS = 24 * HOUR_SECONDS;
257
+ /** Upper bound for a Schedule minimum interval: a 5-field cron's coarsest single-field cadence is hourly. */
258
+ var MAX_MIN_INTERVAL_SECONDS = HOUR_SECONDS;
259
+ /** Parses a comma-separated list of bounded integers; returns undefined if any token is not a plain integer in range. */
260
+ var parseList = (field, min, max) => {
261
+ const tokens = field.split(",");
262
+ const values = tokens.map((token) => parseBoundedUInt(token, min, max)).filter((value) => value !== void 0);
263
+ return values.length === tokens.length && values.length > 0 ? values : void 0;
264
+ };
265
+ /**
266
+ * Smallest cyclic gap between values in a field whose domain wraps at `span` (60 for minutes, 24 for hours),
267
+ * or Infinity for a single value. The wrap is required so e.g. minutes `0,59` register their 1-unit gap
268
+ * (59 → 0 of the next cycle), not just the 59-unit one.
269
+ */
270
+ var minGap = (values, span) => {
271
+ const sorted = [...new Set(values)].sort((lhs, rhs) => lhs - rhs);
272
+ if (sorted.length <= 1) return Number.POSITIVE_INFINITY;
273
+ let gap = Number.POSITIVE_INFINITY;
274
+ for (let index = 0; index < sorted.length; index++) {
275
+ const next = index === sorted.length - 1 ? sorted[0] + span : sorted[index + 1];
276
+ gap = Math.min(gap, next - sorted[index]);
277
+ }
278
+ return gap;
279
+ };
280
+ /** Step value of a `*\/N`, `M/N`, or `A-B/N` field (the cadence between fires), or undefined if not a step form. */
281
+ var parseStep = (field, max) => {
282
+ const match = field.match(/^(?:\*|\d+(?:-\d+)?)\/(\d+)$/);
283
+ return match ? parseBoundedUInt(match[1], 1, max) : void 0;
284
+ };
285
+ /** Minimum seconds between fires implied by a cron's hour field (independent of minute granularity). */
286
+ var hourIntervalSeconds = (hour) => {
287
+ const step = parseStep(hour, 23);
288
+ if (step !== void 0) return step * HOUR_SECONDS;
289
+ if (hour === "*") return HOUR_SECONDS;
290
+ const hours = parseList(hour, 0, 23);
291
+ if (hours) return hours.length > 1 ? minGap(hours, 24) * HOUR_SECONDS : DAY_SECONDS;
292
+ return Number.POSITIVE_INFINITY;
293
+ };
294
+ /**
295
+ * Best-effort minimum seconds between consecutive fires of a 5-field cron expression. Recognises the patterns
296
+ * a too-frequent schedule can take (`* …`, `*\/N …`, explicit minute/hour lists); returns Infinity for
297
+ * expressions it cannot analyse, so unrecognised crons are treated as satisfying any minimum.
298
+ */
299
+ var cronIntervalSeconds = (cron) => {
300
+ const parts = cron.trim().split(/\s+/);
301
+ if (parts.length !== 5) return Number.POSITIVE_INFINITY;
302
+ const [minute, hour] = parts;
303
+ const minuteStep = parseStep(minute, 59);
304
+ if (minuteStep !== void 0) return minuteStep * MINUTE_SECONDS;
305
+ if (minute === "*") return MINUTE_SECONDS;
306
+ const minutes = parseList(minute, 0, 59);
307
+ if (minutes) {
308
+ const minuteGap = minutes.length > 1 ? minGap(minutes, 60) * MINUTE_SECONDS : Number.POSITIVE_INFINITY;
309
+ return Math.min(minuteGap, hourIntervalSeconds(hour));
310
+ }
311
+ return Number.POSITIVE_INFINITY;
312
+ };
313
+ /**
314
+ * Rewrites a cron's minute field so it fires no more often than `minIntervalSeconds`. Used to clamp a custom
315
+ * expression; leaves non-5-field expressions untouched since their cadence cannot be reasoned about.
316
+ */
317
+ var clampCronMinute = (cron, minIntervalSeconds) => {
318
+ const parts = cron.trim().split(/\s+/);
319
+ if (parts.length !== 5) return cron;
320
+ const stepMinutes = Math.ceil(minIntervalSeconds / MINUTE_SECONDS);
321
+ parts[0] = stepMinutes >= 60 ? "0" : `*/${stepMinutes}`;
322
+ return parts.join(" ");
323
+ };
324
+ /** Minimum seconds between fires for a recurring {@link ScheduleValue}. */
325
+ var scheduleIntervalSeconds = (value) => {
326
+ switch (value.kind) {
327
+ case "hourly": return HOUR_SECONDS;
328
+ case "daily": return DAY_SECONDS;
329
+ case "weekly": return DAY_SECONDS;
330
+ case "monthly": return 28 * DAY_SECONDS;
331
+ case "custom": return cronIntervalSeconds(value.cron);
332
+ }
333
+ };
334
+ /**
335
+ * Coerces a schedule so it fires no more often than `minIntervalSeconds`. Only `custom` expressions can exceed
336
+ * the limit (structured kinds are hourly or slower), so clamping rewrites the cron's minute field; all other
337
+ * values pass through unchanged.
338
+ */
339
+ var clampSchedule = (value, minIntervalSeconds) => {
340
+ if (value.kind !== "custom" || cronIntervalSeconds(value.cron) >= minIntervalSeconds) return value;
341
+ return {
342
+ kind: "custom",
343
+ cron: clampCronMinute(value.cron, minIntervalSeconds)
344
+ };
345
+ };
346
+ /**
347
+ * Convert a cron expression to a recurring {@link ScheduleValue}. Patterns that Schedule cannot model exactly
348
+ * (sub-hourly intervals, multi-day months, etc.) fall back to the `custom` kind preserving the raw expression.
349
+ */
350
+ var cronToSchedule = (cron) => {
351
+ const spec = fromCron(cron);
352
+ switch (spec.frequency) {
353
+ case "hourly": return spec.interval === 1 ? {
354
+ kind: "hourly",
355
+ minute: spec.minute
356
+ } : {
357
+ kind: "custom",
358
+ cron
359
+ };
360
+ case "daily": return {
361
+ kind: "daily",
362
+ time: joinTime(spec.hour, spec.minute)
363
+ };
364
+ case "weekly": return {
365
+ kind: "weekly",
366
+ time: joinTime(spec.hour, spec.minute),
367
+ days: [...spec.daysOfWeek]
368
+ };
369
+ case "monthly": return spec.daysOfMonth.length === 1 ? {
370
+ kind: "monthly",
371
+ day: spec.daysOfMonth[0],
372
+ time: joinTime(spec.hour, spec.minute)
373
+ } : {
374
+ kind: "custom",
375
+ cron
376
+ };
377
+ default: return {
378
+ kind: "custom",
379
+ cron
380
+ };
381
+ }
382
+ };
383
+ //#endregion
384
+ //#region src/components/Schedule/types.ts
385
+ var MinutelySpec = Schema.Struct({
386
+ frequency: Schema.Literal("minutely").annotations({ title: "Frequency" }),
387
+ interval: Schema.Number.pipe(Schema.int(), Schema.between(1, 59)).annotations({
388
+ title: "Every (minutes)",
389
+ description: "1–59"
390
+ })
391
+ });
392
+ var HourlySpec = Schema.Struct({
393
+ frequency: Schema.Literal("hourly").annotations({ title: "Frequency" }),
394
+ interval: Schema.Number.pipe(Schema.int(), Schema.between(1, 23)).annotations({
395
+ title: "Every (hours)",
396
+ description: "1–23"
397
+ }),
398
+ minute: Schema.Number.pipe(Schema.int(), Schema.between(0, 59)).annotations({
399
+ title: "At minute",
400
+ description: "0–59"
401
+ })
402
+ });
403
+ var DailySpec = Schema.Struct({
404
+ frequency: Schema.Literal("daily").annotations({ title: "Frequency" }),
405
+ hour: Schema.Number.pipe(Schema.int(), Schema.between(0, 23)).annotations({
406
+ title: "Hour",
407
+ description: "0–23"
408
+ }),
409
+ minute: Schema.Number.pipe(Schema.int(), Schema.between(0, 59)).annotations({
410
+ title: "Minute",
411
+ description: "0–59"
412
+ })
413
+ });
414
+ var DayOfWeek = Schema.Literal("sun", "mon", "tue", "wed", "thu", "fri", "sat");
415
+ var WeeklySpec = Schema.Struct({
416
+ frequency: Schema.Literal("weekly").annotations({ title: "Frequency" }),
417
+ daysOfWeek: Schema.Array(DayOfWeek.annotations({ title: "Day" })).annotations({ title: "Days of week" }),
418
+ hour: Schema.Number.pipe(Schema.int(), Schema.between(0, 23)).annotations({
419
+ title: "Hour",
420
+ description: "0–23"
421
+ }),
422
+ minute: Schema.Number.pipe(Schema.int(), Schema.between(0, 59)).annotations({
423
+ title: "Minute",
424
+ description: "0–59"
425
+ })
426
+ });
427
+ var MonthlySpec = Schema.Struct({
428
+ frequency: Schema.Literal("monthly").annotations({ title: "Frequency" }),
429
+ daysOfMonth: Schema.Array(Schema.Number.pipe(Schema.int(), Schema.between(1, 31)).annotations({ title: "Day" })).annotations({ title: "Days of month" }),
430
+ hour: Schema.Number.pipe(Schema.int(), Schema.between(0, 23)).annotations({
431
+ title: "Hour",
432
+ description: "0–23"
433
+ }),
434
+ minute: Schema.Number.pipe(Schema.int(), Schema.between(0, 59)).annotations({
435
+ title: "Minute",
436
+ description: "0–59"
437
+ })
438
+ });
439
+ var CustomSpec = Schema.Struct({
440
+ frequency: Schema.Literal("custom").annotations({ title: "Frequency" }),
441
+ cronExpression: Schema.String.annotations({
442
+ title: "Cron expression",
443
+ description: "e.g. 0 9 * * MON-FRI"
444
+ })
445
+ });
446
+ var CronSpec = Schema.Union(MinutelySpec, HourlySpec, DailySpec, WeeklySpec, MonthlySpec, CustomSpec).annotations({ title: "" });
447
+ var FrequencyDefaults = {
448
+ minutely: {
449
+ frequency: "minutely",
450
+ interval: 15
451
+ },
452
+ hourly: {
453
+ frequency: "hourly",
454
+ interval: 1,
455
+ minute: 0
456
+ },
457
+ daily: {
458
+ frequency: "daily",
459
+ hour: 9,
460
+ minute: 0
461
+ },
462
+ weekly: {
463
+ frequency: "weekly",
464
+ daysOfWeek: ["mon"],
465
+ hour: 9,
466
+ minute: 0
467
+ },
468
+ monthly: {
469
+ frequency: "monthly",
470
+ daysOfMonth: [1],
471
+ hour: 9,
472
+ minute: 0
473
+ },
474
+ custom: {
475
+ frequency: "custom",
476
+ cronExpression: "* * * * *"
477
+ }
478
+ };
479
+ //#endregion
480
+ //#region src/components/Schedule/days.ts
481
+ var Days = [
482
+ {
483
+ value: "mon",
484
+ label: "Mon"
485
+ },
486
+ {
487
+ value: "tue",
488
+ label: "Tue"
489
+ },
490
+ {
491
+ value: "wed",
492
+ label: "Wed"
493
+ },
494
+ {
495
+ value: "thu",
496
+ label: "Thu"
497
+ },
498
+ {
499
+ value: "fri",
500
+ label: "Fri"
501
+ },
502
+ {
503
+ value: "sat",
504
+ label: "Sat"
505
+ },
506
+ {
507
+ value: "sun",
508
+ label: "Sun"
509
+ }
510
+ ];
511
+ //#endregion
512
+ //#region src/components/Schedule/describe-schedule.ts
513
+ /** Human-readable summary of the schedule, suitable for the header. */
514
+ var DAY_NAMES = {
515
+ mon: "Monday",
516
+ tue: "Tuesday",
517
+ wed: "Wednesday",
518
+ thu: "Thursday",
519
+ fri: "Friday",
520
+ sat: "Saturday",
521
+ sun: "Sunday"
522
+ };
523
+ var withZone = (text, timezone) => timezone ? `${text} ${timezone}` : text;
524
+ var formatTime = (time) => {
525
+ const [h, m] = time.split(":").map(Number);
526
+ if (Number.isNaN(h) || Number.isNaN(m)) return time;
527
+ const period = h < 12 ? "AM" : "PM";
528
+ return `${h % 12 === 0 ? 12 : h % 12}:${String(m).padStart(2, "0")} ${period}`;
529
+ };
530
+ var describeSchedule = (value, timezone) => {
531
+ switch (value.kind) {
532
+ case "hourly": return `Runs every hour at minute ${value.minute}`;
533
+ case "daily": return withZone(`Runs every day at ${formatTime(value.time)}`, timezone);
534
+ case "weekly": return withZone(`Runs every ${value.days.length === 0 ? "no days" : value.days.length === 1 ? DAY_NAMES[value.days[0]] : Days.filter((d) => value.days.includes(d.value)).map((d) => d.label).join(", ")} at ${formatTime(value.time)}`, timezone);
535
+ case "monthly": return withZone(`Runs monthly on day ${value.day} at ${formatTime(value.time)}`, timezone);
536
+ case "custom": return withZone(describeCron(value.cron), timezone);
537
+ }
538
+ };
539
+ //#endregion
540
+ //#region src/components/Schedule/Schedule.tsx
541
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-routine/src/components/Schedule/Schedule.tsx";
542
+ var ScheduleKinds = [
543
+ "hourly",
544
+ "daily",
545
+ "weekly",
546
+ "monthly",
547
+ "custom"
548
+ ];
549
+ var isScheduleKind = (value) => ScheduleKinds.includes(value);
550
+ var DEFAULT_TIME = "08:00";
551
+ /** Default minimum interval: a schedule may fire at most once every 60s (the finest 5-field cron granularity). */
552
+ var DEFAULT_MIN_INTERVAL_SECONDS = 60;
553
+ /** 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. */
554
+ var normalizeMinInterval = (minInterval) => {
555
+ return Math.min(MAX_MIN_INTERVAL_SECONDS, Math.max(DEFAULT_MIN_INTERVAL_SECONDS, Math.round(Number.isFinite(minInterval) ? minInterval : DEFAULT_MIN_INTERVAL_SECONDS)));
556
+ };
557
+ var KIND_LABEL_KEYS = {
558
+ hourly: "schedule.kind.hourly.label",
559
+ daily: "schedule.kind.daily.label",
560
+ weekly: "schedule.kind.weekly.label",
561
+ monthly: "schedule.kind.monthly.label",
562
+ custom: "schedule.kind.custom.label"
563
+ };
564
+ var DEFAULTS = {
565
+ hourly: {
566
+ kind: "hourly",
567
+ minute: 0
568
+ },
569
+ daily: {
570
+ kind: "daily",
571
+ time: DEFAULT_TIME
572
+ },
573
+ weekly: {
574
+ kind: "weekly",
575
+ time: DEFAULT_TIME,
576
+ days: ["mon"]
577
+ },
578
+ monthly: {
579
+ kind: "monthly",
580
+ day: 1,
581
+ time: DEFAULT_TIME
582
+ },
583
+ custom: {
584
+ kind: "custom",
585
+ cron: "0 9 * * 1"
586
+ }
587
+ };
588
+ var pad = (value) => String(value).padStart(2, "0");
589
+ /**
590
+ * Switch to a different kind, preserving the current schedule's timing by routing it through its cron
591
+ * representation. The cron is the canonical carrier: each target kind reuses whatever fields it supports
592
+ * (time-of-day, weekdays, day-of-month), falling back to the kind's default for fields the cron doesn't hold.
593
+ */
594
+ var switchKind = (current, kind) => {
595
+ const cron = scheduleToCron(current);
596
+ const spec = cron ? fromCron(cron) : void 0;
597
+ const [defaultHour, defaultMinute] = DEFAULT_TIME.split(":").map(Number);
598
+ const minute = spec && "minute" in spec ? spec.minute : defaultMinute;
599
+ const time = `${pad(spec && "hour" in spec ? spec.hour : defaultHour)}:${pad(minute)}`;
600
+ switch (kind) {
601
+ case "hourly": return {
602
+ kind: "hourly",
603
+ minute
604
+ };
605
+ case "daily": return {
606
+ kind: "daily",
607
+ time
608
+ };
609
+ case "weekly": return {
610
+ kind: "weekly",
611
+ time,
612
+ days: spec?.frequency === "weekly" ? [...spec.daysOfWeek] : DEFAULTS.weekly.days
613
+ };
614
+ case "monthly": return {
615
+ kind: "monthly",
616
+ time,
617
+ day: spec?.frequency === "monthly" ? spec.daysOfMonth[0] : DEFAULTS.monthly.day
618
+ };
619
+ case "custom": return {
620
+ kind: "custom",
621
+ cron: cron ?? DEFAULTS.custom.cron
622
+ };
623
+ }
624
+ };
625
+ var ScheduleContext = createContext(null);
626
+ var useScheduleContext = (consumer) => {
627
+ const context = useContext(ScheduleContext);
628
+ invariant(context, `${consumer} must be used within Schedule.Root`, {
629
+ "~LogMeta": "~LogMeta",
630
+ F: __dxlog_file,
631
+ L: 148,
632
+ S: void 0,
633
+ A: ["context", "`${consumer} must be used within Schedule.Root`"]
634
+ });
635
+ return context;
636
+ };
637
+ /**
638
+ * Schedule picker root: provides the shared {@link Column} grid (all rows align to the same gutters)
639
+ * and the schedule state context. Controllable via `value`/`onValueChange`, or self-managing via
640
+ * `defaultValue`. Compose with `Schedule.Header`, `Schedule.Kind`, `Schedule.Body`, `Schedule.Description`.
641
+ */
642
+ var ScheduleRoot = composable(({ children, value: valueProp, defaultValue, onValueChange, kinds = ScheduleKinds, minInterval: minIntervalProp = DEFAULT_MIN_INTERVAL_SECONDS, timezone, ...props }, forwardedRef) => {
643
+ const minInterval = normalizeMinInterval(minIntervalProp);
644
+ const [value, setValue] = useState(() => clampSchedule(valueProp ?? defaultValue ?? DEFAULTS.weekly, minInterval));
645
+ const handleValueChange = useCallback((next) => {
646
+ const clamped = clampSchedule(next, minInterval);
647
+ setValue(clamped);
648
+ onValueChange?.(clamped);
649
+ }, [onValueChange, minInterval]);
650
+ const allowedKinds = kinds.filter((kind) => kind === "custom" || scheduleIntervalSeconds(DEFAULTS[kind]) >= minInterval);
651
+ return /* @__PURE__ */ jsx(ScheduleContext.Provider, {
652
+ value: {
653
+ value: clampSchedule(valueProp ?? value, minInterval),
654
+ onValueChange: handleValueChange,
655
+ kinds: allowedKinds,
656
+ minInterval,
657
+ timezone
658
+ },
659
+ children: /* @__PURE__ */ jsx("div", {
660
+ ...composableProps(props, { classNames: "flex flex-col gap-y-3" }),
661
+ ref: forwardedRef,
662
+ children
663
+ })
664
+ });
665
+ });
666
+ ScheduleRoot.displayName = "Schedule.Root";
667
+ /**
668
+ * Summary row laid out on the shared grid: the icon in the leading gutter (column 1), the schedule
669
+ * description (or `children`) in the center column, and an optional close button in the trailing gutter
670
+ * (column 3).
671
+ */
672
+ var ScheduleHeader = forwardRef(({ classNames }, forwardedRef) => {
673
+ const { t } = useTranslation(meta.profile.key);
674
+ const { value, timezone } = useScheduleContext("Schedule.Header");
675
+ return /* @__PURE__ */ jsx("p", {
676
+ className: mx("grow truncate text-description", classNames),
677
+ children: describeSchedule(value, timezone)
678
+ });
679
+ });
680
+ ScheduleHeader.displayName = "Schedule.Header";
681
+ /** Segmented frequency tabs (Once / Hourly / Daily / Weekly / Custom). */
682
+ var ScheduleKindRow = forwardRef(({ classNames }, forwardedRef) => {
683
+ const { t } = useTranslation(meta.profile.key);
684
+ const { value, onValueChange, kinds } = useScheduleContext("Schedule.Kind");
685
+ const handleKindChange = useCallback((kind) => {
686
+ if (isScheduleKind(kind)) onValueChange(switchKind(value, kind));
687
+ }, [value, onValueChange]);
688
+ return /* @__PURE__ */ jsx(ToggleGroup, {
689
+ classNames: "overflow-x-auto scrollbar-none",
690
+ type: "single",
691
+ value: value.kind,
692
+ onValueChange: handleKindChange,
693
+ children: kinds.map((kind) => /* @__PURE__ */ jsx(ToggleGroupItem, {
694
+ value: kind,
695
+ children: t(KIND_LABEL_KEYS[kind])
696
+ }, kind))
697
+ });
698
+ });
699
+ ScheduleKindRow.displayName = "Schedule.Kind";
700
+ /** Per-kind editor for the active frequency. Rendered as a 3-column row so editors can use the gutters. */
701
+ var ScheduleBody = forwardRef(({ classNames }, forwardedRef) => {
702
+ const { value, onValueChange } = useScheduleContext("Schedule.Body");
703
+ return /* @__PURE__ */ jsx(ScheduleEditor, {
704
+ value,
705
+ onChange: onValueChange
706
+ });
707
+ });
708
+ ScheduleBody.displayName = "Schedule.Body";
709
+ var Schedule = {
710
+ Root: ScheduleRoot,
711
+ Header: ScheduleHeader,
712
+ Kind: ScheduleKindRow,
713
+ Body: ScheduleBody
714
+ };
715
+ var Field = ({ label, children, classNames }) => /* @__PURE__ */ jsxs("label", {
716
+ className: mx("flex items-center gap-2 shrink-0", classNames),
717
+ children: [/* @__PURE__ */ jsx("span", {
718
+ className: "text-sm",
719
+ children: label
720
+ }), children]
721
+ });
722
+ var ScheduleEditor = ({ value, onChange }) => {
723
+ const { t } = useTranslation(meta.profile.key);
724
+ switch (value.kind) {
725
+ case "hourly": return /* @__PURE__ */ jsx(Field, {
726
+ label: t("schedule.minute.label"),
727
+ children: /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.TextInput, {
728
+ type: "number",
729
+ min: 0,
730
+ max: 59,
731
+ step: 1,
732
+ classNames: "w-15",
733
+ value: String(value.minute),
734
+ onChange: (event) => {
735
+ onChange({
736
+ kind: "hourly",
737
+ minute: Math.min(59, Math.max(0, Math.round(Number(event.target.value) || 0)))
738
+ });
739
+ }
740
+ }) })
741
+ });
742
+ case "daily": return /* @__PURE__ */ jsx(Field, {
743
+ label: t("schedule.at.label"),
744
+ children: /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.Time, {
745
+ hourCycle: 12,
746
+ value: value.time,
747
+ onValueChange: (time) => onChange({
748
+ kind: "daily",
749
+ time
750
+ })
751
+ }) })
752
+ });
753
+ case "weekly": return /* @__PURE__ */ jsxs("div", {
754
+ className: "@container dx-inline-size-container min-w-0 flex justify-between items-center gap-2 overflow-x-auto scrollbar-none",
755
+ children: [/* @__PURE__ */ jsx(Field, {
756
+ label: t("schedule.at.label"),
757
+ children: /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.Time, {
758
+ hourCycle: 12,
759
+ value: value.time,
760
+ onValueChange: (time) => onChange({
761
+ ...value,
762
+ time
763
+ })
764
+ }) })
765
+ }), /* @__PURE__ */ jsxs("div", {
766
+ className: "flex shrink-0 items-center gap-2",
767
+ children: [/* @__PURE__ */ jsx("span", {
768
+ className: "shrink-0 text-sm",
769
+ children: t("schedule.on.label")
770
+ }), /* @__PURE__ */ jsx("div", {
771
+ className: "grid w-max shrink-0 grid-cols-7 gap-x-2",
772
+ children: Days.map(({ value: day, label }) => {
773
+ const checked = value.days.includes(day);
774
+ return /* @__PURE__ */ jsx("div", {
775
+ className: "flex shrink-0 items-center gap-1",
776
+ children: /* @__PURE__ */ jsxs(Input.Root, { children: [
777
+ /* @__PURE__ */ jsx(Input.Checkbox, {
778
+ checked,
779
+ onCheckedChange: (next) => {
780
+ const nextDays = next ? Days.map((d) => d.value).filter((d) => d === day || value.days.includes(d)) : value.days.filter((d) => d !== day);
781
+ onChange({
782
+ ...value,
783
+ days: nextDays.length > 0 ? nextDays : value.days
784
+ });
785
+ }
786
+ }),
787
+ /* @__PURE__ */ jsx(Input.Label, {
788
+ classNames: "hidden @min-[32rem]:inline-block text-xs uppercase",
789
+ children: label
790
+ }),
791
+ /* @__PURE__ */ jsx(Input.Label, {
792
+ classNames: "inline-block @min-[32rem]:hidden text-xs",
793
+ children: label.charAt(0)
794
+ })
795
+ ] })
796
+ }, day);
797
+ })
798
+ })]
799
+ })]
800
+ });
801
+ case "monthly": return /* @__PURE__ */ jsxs("div", {
802
+ className: "flex items-center gap-3",
803
+ children: [/* @__PURE__ */ jsx(Field, {
804
+ label: t("schedule.day.label"),
805
+ children: /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.TextInput, {
806
+ type: "number",
807
+ min: 1,
808
+ max: 31,
809
+ step: 1,
810
+ classNames: "w-15",
811
+ value: String(value.day),
812
+ onChange: (event) => {
813
+ const day = Math.min(31, Math.max(1, Math.round(Number(event.target.value) || 1)));
814
+ onChange({
815
+ ...value,
816
+ day
817
+ });
818
+ }
819
+ }) })
820
+ }), /* @__PURE__ */ jsx(Field, {
821
+ label: t("schedule.at.label"),
822
+ children: /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.Time, {
823
+ hourCycle: 12,
824
+ value: value.time,
825
+ onValueChange: (time) => onChange({
826
+ ...value,
827
+ time
828
+ })
829
+ }) })
830
+ })]
831
+ });
832
+ case "custom": return /* @__PURE__ */ jsx(Field, {
833
+ label: t("schedule.cron.label"),
834
+ children: /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.TextInput, {
835
+ classNames: "w-50 tabular-nums",
836
+ placeholder: "0 9 * * MON-FRI",
837
+ value: value.cron,
838
+ onChange: (event) => onChange({
839
+ kind: "custom",
840
+ cron: event.target.value
841
+ })
842
+ }) })
843
+ });
844
+ }
845
+ };
846
+ //#endregion
847
+ //#region src/components/TriggerEditor/trigger-kind-icon.ts
848
+ /** Icon for a trigger kind, shared by the picker rows and the selected-variant editor header. */
849
+ var OPTIONS = [
850
+ {
851
+ kind: "timer",
852
+ icon: "ph--clock-countdown--regular"
853
+ },
854
+ {
855
+ kind: "feed",
856
+ icon: "ph--cards-three--regular"
857
+ },
858
+ {
859
+ kind: "subscription",
860
+ icon: "ph--funnel--regular"
861
+ },
862
+ {
863
+ kind: "webhook",
864
+ icon: "ph--webhooks-logo--regular",
865
+ disabled: true
866
+ },
867
+ {
868
+ kind: "email",
869
+ icon: "ph--envelope--regular",
870
+ disabled: true
871
+ }
872
+ ];
873
+ //#endregion
874
+ //#region src/components/TriggerEditor/TriggerKindSelector.tsx
875
+ /**
876
+ * Single-select list of pluggable trigger variants (Schedule / Feed / Query / Webhook / Email): each row
877
+ * shows an icon, title and description. Built on {@link Listbox} (role=listbox/option, arrow-key navigation);
878
+ * selecting a row emits its kind. Selection is transient — the parent swaps in the variant editor on change.
879
+ */
880
+ var TriggerKindSelector = ({ onChange }) => {
881
+ const { t } = useTranslation(meta.profile.key);
882
+ const handleValueChange = useCallback((id) => {
883
+ const option = OPTIONS.find((option) => option.kind === id);
884
+ if (option) onChange(option.kind);
885
+ }, [onChange]);
886
+ return /* @__PURE__ */ jsx(Listbox.Root, {
887
+ onValueChange: handleValueChange,
888
+ children: /* @__PURE__ */ jsx(Listbox.Content, {
889
+ classNames: "gap-1",
890
+ "aria-label": t("trigger-kind.placeholder"),
891
+ children: OPTIONS.map(({ kind, icon, disabled }) => /* @__PURE__ */ jsx(Listbox.Item, {
892
+ id: kind,
893
+ disabled,
894
+ classNames: "dx-input-surface rounded-sm",
895
+ children: /* @__PURE__ */ jsx(Listbox.ItemContent, {
896
+ icon: /* @__PURE__ */ jsx(Icon, {
897
+ icon,
898
+ size: 5,
899
+ classNames: "text-description"
900
+ }),
901
+ title: /* @__PURE__ */ jsx("span", {
902
+ className: "font-medium",
903
+ children: t(`trigger-kind.${kind}.label`)
904
+ }),
905
+ description: t(`trigger-kind.${kind}.description`)
906
+ })
907
+ }, kind))
908
+ })
909
+ });
910
+ };
911
+ //#endregion
912
+ //#region src/components/TriggerEditor/TriggerEditor.tsx
913
+ var RECURRING_KINDS = [
914
+ "hourly",
915
+ "daily",
916
+ "weekly",
917
+ "monthly",
918
+ "custom"
919
+ ];
920
+ var EnabledForm = Type.getSchema(Trigger.Trigger).pipe(Schema.pick("enabled", "remote"));
921
+ var TimerSpecForm = Schema.extend(Schema.Struct({
922
+ kind: Schema.Literal("timer"),
923
+ cron: Schema.String.pipe(Schema.annotations({ title: "Schedule (cron)" }), Schema.optional)
924
+ }), EnabledForm);
925
+ var SubscriptionSpecForm = Schema.extend(Schema.Struct({
926
+ kind: Schema.Literal("subscription"),
927
+ typename: Schema.String.pipe(Schema.annotations({ title: "Type" }), Schema.optional),
928
+ deep: Schema.Boolean.pipe(Schema.annotations({ title: "Nested" }), Schema.optional),
929
+ delay: Schema.Number.pipe(Schema.annotations({ title: "Delay (ms)" }), Schema.optional)
930
+ }), EnabledForm);
931
+ var WebhookSpecForm = Schema.extend(Schema.Struct({
932
+ kind: Schema.Literal("webhook"),
933
+ method: Schema.String.pipe(Schema.annotations({ title: "Method" }), Schema.optional),
934
+ port: Schema.Number.pipe(Schema.annotations({ title: "Port" }), Schema.optional)
935
+ }), EnabledForm);
936
+ var FeedSpecForm = Schema.extend(Schema.Struct({
937
+ kind: Schema.Literal("feed"),
938
+ feed: Ref.Ref(Feed.Feed).pipe(ParentLabelAnnotation.set(true), Schema.annotations({ title: "Feed" }), Schema.optional)
939
+ }), EnabledForm);
940
+ var EmailSpecForm = Schema.extend(Schema.Struct({ kind: Schema.Literal("email") }), EnabledForm);
941
+ var TriggerForm = Schema.Union(TimerSpecForm, SubscriptionSpecForm, WebhookSpecForm, FeedSpecForm, EmailSpecForm);
942
+ /** Project a trigger spec onto the form's discriminated-union members. */
943
+ var triggerFormValues = (spec) => {
944
+ switch (spec?.kind) {
945
+ case "subscription": return {
946
+ kind: "subscription",
947
+ typename: spec.query?.raw,
948
+ deep: spec.options?.deep,
949
+ delay: spec.options?.delay
950
+ };
951
+ case "feed": return {
952
+ kind: "feed",
953
+ feed: spec.feed
954
+ };
955
+ case "webhook": return {
956
+ kind: "webhook",
957
+ method: spec.method,
958
+ port: spec.port
959
+ };
960
+ case "email": return { kind: "email" };
961
+ case "timer": return {
962
+ kind: "timer",
963
+ cron: spec.cron
964
+ };
965
+ default: return {};
966
+ }
967
+ };
968
+ var DEFAULT_TIMER_CRON = toCron(FrequencyDefaults.daily);
969
+ /** Build the subscription query: filter by the chosen type, or match everything until one is picked. */
970
+ var subscriptionQuery = (typename) => typename ? Query.select(Filter.type(DXN.make(typename))) : Query.select(Filter.everything());
971
+ /** Build a trigger spec from the form's values. */
972
+ var triggerFormSpec = (values) => {
973
+ switch (values.kind) {
974
+ case "subscription": {
975
+ const hasOptions = values.deep != null || values.delay != null;
976
+ return {
977
+ kind: "subscription",
978
+ query: {
979
+ raw: values.typename,
980
+ ast: subscriptionQuery(values.typename).ast
981
+ },
982
+ options: hasOptions ? {
983
+ deep: values.deep,
984
+ delay: values.delay
985
+ } : void 0
986
+ };
987
+ }
988
+ case "feed": return {
989
+ kind: "feed",
990
+ feed: values.feed
991
+ };
992
+ case "webhook": return Trigger.specWebhook({
993
+ method: values.method,
994
+ port: values.port
995
+ });
996
+ case "email": return Trigger.specEmail();
997
+ default: return Trigger.specTimer(values.cron || DEFAULT_TIMER_CRON);
998
+ }
999
+ };
1000
+ var TriggerEditor = ({ classNames, db, routine, trigger, readonly }) => {
1001
+ const { t } = useTranslation(meta.profile.key);
1002
+ const { defaultValues, fieldMap, kind, reset, handleValuesChanged } = useTriggerForm(routine, trigger);
1003
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Form.Root, {
1004
+ schema: TriggerForm,
1005
+ db,
1006
+ readonly,
1007
+ fieldMap,
1008
+ defaultValues,
1009
+ onValuesChanged: handleValuesChanged,
1010
+ children: /* @__PURE__ */ jsxs(Form.Content, {
1011
+ classNames: mx(kind && "pb-2 dx-card-surface border border-separator rounded-xs", classNames),
1012
+ children: [kind ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
1013
+ className: "flex items-center",
1014
+ children: [/* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.Label, {
1015
+ classNames: "pl-2 grow truncate",
1016
+ children: t(`trigger-kind.${kind}.label`)
1017
+ }) }), !readonly && /* @__PURE__ */ jsx(IconButton, {
1018
+ variant: "ghost",
1019
+ icon: "ph--x--regular",
1020
+ iconOnly: true,
1021
+ square: true,
1022
+ label: t("trigger-kind.clear.label"),
1023
+ onClick: reset
1024
+ })]
1025
+ }), /* @__PURE__ */ jsx(Form.FieldSet, { classNames: "px-2" })] }) : /* @__PURE__ */ jsx(Form.FieldSet, {}), kind === "email" && /* @__PURE__ */ jsx("p", {
1026
+ className: "px-2 text-sm text-description",
1027
+ children: t("trigger-kind.email-note.message")
1028
+ })]
1029
+ })
1030
+ }, `${trigger?.id ?? "new"}:${trigger?.spec?.kind ?? "none"}`) });
1031
+ };
1032
+ /** Selects the ECHO object type to watch (subscription `typename`) from the space + registry schemas. */
1033
+ var TypeSelectField = (props) => {
1034
+ const types = useQuery(props.db, Query.select(Filter.type(Type.Type)).from(Scope.space(), Scope.registry()));
1035
+ const options = useMemo(() => types.filter((type) => !Type.isTypeKind(type)).map((type) => Type.getTypename(type)).filter((typename) => !!typename).map((typename) => ({
1036
+ value: typename,
1037
+ label: typename
1038
+ })), [types]);
1039
+ return /* @__PURE__ */ jsx(SelectField, {
1040
+ ...props,
1041
+ options
1042
+ });
1043
+ };
1044
+ TypeSelectField.displayName = "TriggerEditor.TypeSelectField";
1045
+ /** Edits the cron via the Schedule picker (recurring kinds only) with a live cronstrue description below it. */
1046
+ var CronField = (props) => {
1047
+ const cron = props.getValue() || DEFAULT_TIMER_CRON;
1048
+ const initial = useMemo(() => cronToSchedule(cron), []);
1049
+ const handleChange = useCallback((value) => {
1050
+ const next = scheduleToCron(value);
1051
+ if (next) props.onValueChange(props.type, next);
1052
+ }, [props.type, props.onValueChange]);
1053
+ return /* @__PURE__ */ jsxs(Schedule.Root, {
1054
+ kinds: RECURRING_KINDS,
1055
+ defaultValue: initial,
1056
+ onValueChange: handleChange,
1057
+ children: [
1058
+ /* @__PURE__ */ jsx(Schedule.Header, {}),
1059
+ /* @__PURE__ */ jsx(Schedule.Kind, {}),
1060
+ /* @__PURE__ */ jsx(Schedule.Body, {})
1061
+ ]
1062
+ });
1063
+ };
1064
+ CronField.displayName = "TriggerEditor.CronField";
1065
+ /** Form state for the Trigger section: the chosen variant spec, plus create-on-first-edit handler. */
1066
+ var useTriggerForm = (routine, trigger) => {
1067
+ const methodOptions = useMemo(() => [{
1068
+ value: "GET",
1069
+ label: "GET"
1070
+ }, {
1071
+ value: "POST",
1072
+ label: "POST"
1073
+ }], []);
1074
+ const fieldMap = useMemo(() => ({
1075
+ kind: (props) => props.getValue() ? null : /* @__PURE__ */ jsx(TriggerKindSelector, { onChange: (next) => props.onValueChange(props.type, next) }),
1076
+ cron: (props) => /* @__PURE__ */ jsx(CronField, { ...props }),
1077
+ method: (props) => /* @__PURE__ */ jsx(SelectField, {
1078
+ ...props,
1079
+ options: methodOptions
1080
+ }),
1081
+ typename: (props) => /* @__PURE__ */ jsx(TypeSelectField, { ...props })
1082
+ }), [methodOptions]);
1083
+ const defaultValues = useMemo(() => ({
1084
+ ...triggerFormValues(trigger?.spec),
1085
+ enabled: trigger?.enabled,
1086
+ remote: trigger?.remote
1087
+ }), [
1088
+ trigger,
1089
+ trigger?.spec,
1090
+ trigger?.enabled,
1091
+ trigger?.remote
1092
+ ]);
1093
+ const [kind, setKind] = useState(() => triggerFormValues(trigger?.spec).kind);
1094
+ return {
1095
+ defaultValues,
1096
+ fieldMap,
1097
+ kind,
1098
+ reset: useCallback(() => {
1099
+ setKind(void 0);
1100
+ if (trigger) Obj.update(trigger, (trigger) => {
1101
+ trigger.spec = void 0;
1102
+ });
1103
+ }, [trigger]),
1104
+ handleValuesChanged: useCallback((values) => {
1105
+ if (!values.kind) return;
1106
+ const spec = triggerFormSpec(values);
1107
+ setKind(values.kind);
1108
+ const enabled = values.enabled === true;
1109
+ const remote = values.remote;
1110
+ if (trigger) Obj.update(trigger, (trigger) => {
1111
+ trigger.spec = spec;
1112
+ trigger.enabled = enabled;
1113
+ trigger.remote = remote;
1114
+ });
1115
+ else {
1116
+ const created = Trigger.make({
1117
+ spec,
1118
+ enabled,
1119
+ remote
1120
+ });
1121
+ Obj.setParent(created, routine);
1122
+ Obj.update(routine, (routine) => {
1123
+ routine.triggers.push(Ref.make(created));
1124
+ });
1125
+ wireTriggers(routine);
1126
+ }
1127
+ }, [routine, trigger])
1128
+ };
1129
+ };
1130
+ //#endregion
1131
+ //#region src/components/RoutineForm/RoutineForm.tsx
1132
+ var GeneralForm = Type.getSchema(Routine.Routine).pipe(Schema.pick("name", "description"));
1133
+ /**
1134
+ * Composite routine form: the general fields (name + description) are the outer {@link Form},
1135
+ * with the Actions and Triggers sections rendered as sub-forms inside its content:
1136
+ * - Actions — Operation/Instructions variants chosen via a button group (single action; `spec` isn't an array).
1137
+ * - Triggers — the {@link TriggerEditor}.
1138
+ *
1139
+ * The sub-forms read and autosave the routine's owned instructions and primary trigger directly off the
1140
+ * `routine` graph (live editing); `readonly` displays them without edit affordances. The optional Save/Cancel
1141
+ * row is used only by the companion's create-from-template flow.
1142
+ *
1143
+ * Created with `composable()` so it carries the COMPOSABLE marker and can be the child of
1144
+ * `Panel.Content asChild` (forwards ref and merges layout props onto the scroll viewport).
1145
+ */
1146
+ var RoutineForm = composable(({ db, routine, readonly = false, onSave, onCancel, ...props }, forwardedRef) => {
1147
+ const { t } = useTranslation(meta.profile.key);
1148
+ const [auto, updateAuto] = useObject(routine);
1149
+ const trigger = usePrimaryTrigger(routine);
1150
+ const defaultValues = useMemo(() => ({
1151
+ name: auto.name,
1152
+ description: auto.description
1153
+ }), [routine]);
1154
+ const handleValuesChanged = useCallback((values) => {
1155
+ updateAuto((routine) => {
1156
+ routine.name = values.name;
1157
+ routine.description = values.description;
1158
+ });
1159
+ }, [updateAuto]);
1160
+ return /* @__PURE__ */ jsx(Form.Root, {
1161
+ schema: GeneralForm,
1162
+ readonly,
1163
+ defaultValues,
1164
+ onValuesChanged: handleValuesChanged,
1165
+ onSave,
1166
+ onCancel,
1167
+ children: /* @__PURE__ */ jsx(Form.Viewport, {
1168
+ scroll: true,
1169
+ ...composableProps(props),
1170
+ ref: forwardedRef,
1171
+ children: /* @__PURE__ */ jsxs(Form.Content, { children: [
1172
+ /* @__PURE__ */ jsx(Form.FieldSet, {}),
1173
+ /* @__PURE__ */ jsx(Section, {
1174
+ title: t("actions.title"),
1175
+ children: /* @__PURE__ */ jsx(ActionEditor, {
1176
+ db,
1177
+ routine,
1178
+ readonly
1179
+ })
1180
+ }),
1181
+ /* @__PURE__ */ jsx(Section, {
1182
+ title: t("triggers.title"),
1183
+ children: /* @__PURE__ */ jsx(TriggerEditor, {
1184
+ db,
1185
+ routine,
1186
+ trigger,
1187
+ readonly
1188
+ })
1189
+ }),
1190
+ onSave && /* @__PURE__ */ jsx(Form.Actions, {})
1191
+ ] })
1192
+ })
1193
+ });
1194
+ });
1195
+ /** Lightweight labelled grouping for a sub-form (no `Settings` chrome). */
1196
+ var Section = ({ title, children }) => /* @__PURE__ */ jsxs("div", {
1197
+ className: "flex flex-col mbs-4",
1198
+ children: [/* @__PURE__ */ jsx(Form.Label, {
1199
+ standalone: true,
1200
+ label: title
1201
+ }), children]
1202
+ });
1203
+ /**
1204
+ * Single action: an Operation (the routine's `spec.runnable`) or an owned Instructions edited inline. The
1205
+ * action kind is derived from the routine's `spec` — an absent spec means "operation, none chosen yet" (a
1206
+ * scaffolded routine always carries an instructions spec, so the only way to clear it is switching to an
1207
+ * operation). `makeRoutine` establishes the owned-instructions wiring when the routine is scaffolded.
1208
+ */
1209
+ var ActionEditor = ({ db, routine: routineProp, readonly }) => {
1210
+ const operations = useOperations(db);
1211
+ const [routine, updateRoutine] = useObject(routineProp);
1212
+ const kind = routine.spec?.kind ?? "runnable";
1213
+ const operationRef = Routine.runnableRef(routine);
1214
+ const instructions = Routine.instructionsRef(routine)?.target;
1215
+ const handleOperationChange = useCallback((operation) => {
1216
+ updateRoutine((routine) => {
1217
+ routine.spec = operation ? {
1218
+ kind: "runnable",
1219
+ runnable: operation
1220
+ } : void 0;
1221
+ });
1222
+ wireTriggers(routineProp);
1223
+ }, [updateRoutine, routineProp]);
1224
+ const handleKindChange = useCallback((next) => {
1225
+ updateRoutine((routine) => {
1226
+ if (next === "runnable") routine.spec = void 0;
1227
+ else if (routine.spec?.kind !== "instructions") {
1228
+ const instructions = Instructions.make({});
1229
+ Obj.setParent(instructions, routine);
1230
+ routine.spec = {
1231
+ kind: "instructions",
1232
+ instructions: Ref.make(instructions)
1233
+ };
1234
+ }
1235
+ });
1236
+ wireTriggers(routineProp);
1237
+ }, [updateRoutine, routineProp]);
1238
+ return /* @__PURE__ */ jsxs("div", {
1239
+ className: "flex flex-col",
1240
+ children: [!readonly && /* @__PURE__ */ jsx(ActionKindToggle, {
1241
+ value: kind,
1242
+ onChange: handleKindChange
1243
+ }), kind === "runnable" ? /* @__PURE__ */ jsx(OperationEditor, {
1244
+ db,
1245
+ operations,
1246
+ operation: operationRef,
1247
+ onChange: handleOperationChange,
1248
+ readonly
1249
+ }) : instructions ? /* @__PURE__ */ jsx(InstructionsEditor, {
1250
+ db,
1251
+ instructions,
1252
+ readonly
1253
+ }) : null]
1254
+ });
1255
+ };
1256
+ var ActionKindToggle = ({ value, onChange }) => {
1257
+ const { t } = useTranslation(meta.profile.key);
1258
+ return /* @__PURE__ */ jsxs(ToggleGroup, {
1259
+ type: "single",
1260
+ value,
1261
+ onValueChange: (next) => {
1262
+ if (next === "instructions" || next === "runnable") onChange(next);
1263
+ },
1264
+ children: [/* @__PURE__ */ jsx(ToggleGroupItem, {
1265
+ value: "instructions",
1266
+ children: t("action-kind.instructions.label")
1267
+ }), /* @__PURE__ */ jsx(ToggleGroupItem, {
1268
+ value: "runnable",
1269
+ children: t("action-kind.operation.label")
1270
+ })]
1271
+ });
1272
+ };
1273
+ var OperationActionForm = Schema.Struct({ operation: Ref.Ref(Operation.PersistentOperation).pipe(Schema.annotations({ title: "Operation" }), Schema.optional) });
1274
+ var getOperationOptions = (results) => results.filter((operation) => !Obj.instanceOf(Operation.PersistentOperation, operation) || Operation.isVisible(operation)).map((operation) => {
1275
+ const id = Entity.getURI(operation, { prefer: "named" });
1276
+ return {
1277
+ id,
1278
+ label: Entity.getLabel(operation) ?? id,
1279
+ description: Obj.instanceOf(Operation.PersistentOperation, operation) ? Operation.getKey(operation) : void 0
1280
+ };
1281
+ }).sort((left, right) => left.label.localeCompare(right.label));
1282
+ /** Sub-form: ref picker for an Operation. Draws options from the queried operation set (space + registry). */
1283
+ var OperationEditor = ({ db, operations, operation, onChange, readonly }) => {
1284
+ const fieldMap = useMemo(() => ({ operation: (props) => /* @__PURE__ */ jsx(RefField, {
1285
+ ...props,
1286
+ db,
1287
+ useResults: () => operations,
1288
+ getOptions: getOperationOptions
1289
+ }) }), [db, operations]);
1290
+ const defaultValues = useMemo(() => ({ operation }), [operation]);
1291
+ const handleValuesChanged = useCallback((values) => onChange?.(values.operation), [onChange]);
1292
+ return /* @__PURE__ */ jsx(Form.Root, {
1293
+ schema: OperationActionForm,
1294
+ db,
1295
+ readonly,
1296
+ defaultValues,
1297
+ fieldMap,
1298
+ onValuesChanged: handleValuesChanged,
1299
+ children: /* @__PURE__ */ jsx(Form.FieldSet, {})
1300
+ });
1301
+ };
1302
+ /** Operations available to bind as an action (space-resident plus registry / plugin-provided). */
1303
+ var useOperations = (db) => useQuery(db, Query.select(Filter.type(DXN.make(Type.getTypename(Operation.PersistentOperation)))).from(Scope.space(), Scope.registry()));
1304
+ /** Subscribe to the routine and derive its primary (first) trigger. */
1305
+ var usePrimaryTrigger = (routine) => {
1306
+ const [snapshot] = useObject(routine);
1307
+ return useMemo(() => {
1308
+ for (const ref of snapshot.triggers) {
1309
+ const target = ref.target;
1310
+ if (Obj.instanceOf(Trigger.Trigger, target)) return target;
1311
+ }
1312
+ }, [snapshot.triggers]);
1313
+ };
1314
+ //#endregion
1315
+ //#region src/components/CreateRoutinePanel/CreateRoutinePanel.tsx
1316
+ /**
1317
+ * Create panel for routines: a SearchList picker over contributed templates. Selecting one submits
1318
+ * `{ templateId }`; plugin-routine's CreateObjectEntry.createObject resolves the templateId and runs the
1319
+ * template's `scaffold`.
1320
+ */
1321
+ var CreateRoutinePanel = ({ onCreateObject, templates: templatesProp }) => {
1322
+ const { t } = useTranslation(meta.profile.key);
1323
+ const capabilityTemplates = useCapabilities(RoutineCapabilities.Template);
1324
+ const templates = templatesProp ?? capabilityTemplates;
1325
+ const { results, handleSearch } = useSearchListResults({
1326
+ items: useMemo(() => [...templates].filter((template) => template.appliesTo?.(void 0) ?? true).sort((a, b) => a.label.localeCompare(b.label)), [templates]),
1327
+ extract: (template) => template.label
1328
+ });
1329
+ const handleSelect = useCallback((templateId) => {
1330
+ onCreateObject({ templateId });
1331
+ }, [onCreateObject]);
1332
+ return /* @__PURE__ */ jsxs(SearchList.Root, {
1333
+ onSearch: handleSearch,
1334
+ children: [/* @__PURE__ */ jsx(SearchList.Input, {
1335
+ classNames: "mb-form-gap",
1336
+ autoFocus: true,
1337
+ "data-testid": "create-automation-panel.template-input",
1338
+ placeholder: t("create-panel.template.placeholder")
1339
+ }), /* @__PURE__ */ jsx(SearchList.Viewport, { children: results.map((template) => /* @__PURE__ */ jsx(SearchList.Item, {
1340
+ value: template.id,
1341
+ label: template.label,
1342
+ icon: template.icon ?? "ph--lightning--regular",
1343
+ onSelect: () => handleSelect(template.id)
1344
+ }, template.id)) })]
1345
+ });
1346
+ };
1347
+ //#endregion
1348
+ //#region src/components/RoutineCard/RoutineCard.tsx
1349
+ /**
1350
+ * Compact preview of a {@link Routine.Routine}: when it runs. Rendered into the
1351
+ * `AppSurface.CardContent` slot — Card.Root is supplied by the surface host (the project article's
1352
+ * gallery, popovers, related-objects), so this emits Card.Body only. Without it a routine falls back
1353
+ * to the generic form preview, which renders its `spec`/`triggers` internals rather than a summary.
1354
+ */
1355
+ var RoutineCard = ({ subject }) => {
1356
+ const { t } = useTranslation(meta.profile.key);
1357
+ const [routine] = useObject(subject);
1358
+ const [trigger] = useObject(routine.triggers.at(0));
1359
+ const active = trigger?.enabled === true;
1360
+ return /* @__PURE__ */ jsx(Card.Body, { children: /* @__PURE__ */ jsxs(Card.Row, { children: [/* @__PURE__ */ jsx(Card.Block, { children: active && /* @__PURE__ */ jsx(Icon, {
1361
+ icon: "ph--check-circle--regular",
1362
+ classNames: "text-green-text"
1363
+ }) }), /* @__PURE__ */ jsx(Card.Text, {
1364
+ variant: "description",
1365
+ classNames: "line-clamp-2",
1366
+ children: describeTrigger(trigger?.spec, t)
1367
+ })] }) });
1368
+ };
1369
+ RoutineCard.displayName = "RoutineCard";
1370
+ /**
1371
+ * The same sentence the trigger editor shows above the schedule picker. Non-timer kinds have no
1372
+ * parameters worth summarizing, so they reuse the kind description from the trigger-kind picker.
1373
+ */
1374
+ var describeTrigger = (spec, t) => {
1375
+ if (!spec) return t("add-trigger-first.message");
1376
+ return spec.kind === "timer" ? describeSchedule(cronToSchedule(spec.cron)) : t(`trigger-kind.${spec.kind}.description`);
1377
+ };
1378
+ //#endregion
1379
+ //#region src/components/TemplateEditor/extensions/handlebars-extension.ts
1380
+ /**
1381
+ * Simple Handlebars plugin for CodeMirror.
1382
+ * Supports:
1383
+ * - Comments: {{! comment }}
1384
+ * - Commands: {{#command}} {{/command}}
1385
+ * - Variables: {{var}}
1386
+ * - Commands with variables: {{#each items}} {{/each}}
1387
+ */
1388
+ var handlebars = (_ = {}) => {
1389
+ return [
1390
+ handlebarsHighlightPlugin,
1391
+ autocompletion({
1392
+ activateOnTyping: true,
1393
+ aboveCursor: true,
1394
+ closeOnBlur: true,
1395
+ override: [handlebarsCompletions]
1396
+ }),
1397
+ keymap.of(completionKeymap)
1398
+ ];
1399
+ };
1400
+ var regex = {
1401
+ comment: /\{\{!\s*[^}]*\}\}/g,
1402
+ brackets: /\{\{[^}]*\}\}/g,
1403
+ command: /\{\{[#/]([^}]+)\}\}/g,
1404
+ var: /\{\{(?!\s*!)(\w[^}]*)\}\}/g,
1405
+ dxn: /@?(?:echo:\/{1,3}[\w/]+|dxn:[\w.-]+)/g,
1406
+ url: /[\w.-]+\.[\w.-]+\/[\w/]+/g
1407
+ };
1408
+ var tagPadding = "mx-0.5 px-1 rounded-xs";
1409
+ /**
1410
+ * ViewPlugin that decorates Handlebars syntax.
1411
+ */
1412
+ var handlebarsHighlightPlugin = ViewPlugin.fromClass(class {
1413
+ decorations;
1414
+ constructor(view) {
1415
+ this.decorations = this.buildDecorations(view);
1416
+ }
1417
+ update(update) {
1418
+ if (update.docChanged || update.viewportChanged || update.selectionSet) this.decorations = this.buildDecorations(update.view);
1419
+ }
1420
+ buildDecorations(view) {
1421
+ const selection = view.state.selection.main;
1422
+ const decorations = [];
1423
+ for (const { from, to } of view.visibleRanges) {
1424
+ const text = view.state.doc.sliceString(from, to);
1425
+ {
1426
+ let match;
1427
+ while ((match = regex.dxn.exec(text)) !== null) {
1428
+ const start = from + match.index;
1429
+ const end = start + match[0].length;
1430
+ if (!(selection.to > start && selection.from <= end)) decorations.push({
1431
+ from: start,
1432
+ to: end,
1433
+ decoration: Decoration.widget({ widget: new DXNWidget(match[0]) })
1434
+ });
1435
+ }
1436
+ }
1437
+ {
1438
+ let match;
1439
+ while ((match = regex.url.exec(text)) !== null) {
1440
+ const start = from + match.index;
1441
+ const end = start + match[0].length;
1442
+ decorations.push({
1443
+ from: start,
1444
+ to: end,
1445
+ decoration: Decoration.mark({ class: mx$1("dx-tag--blue", tagPadding) })
1446
+ });
1447
+ }
1448
+ }
1449
+ {
1450
+ let match;
1451
+ while ((match = regex.brackets.exec(text)) !== null) {
1452
+ const start = from + match.index;
1453
+ const end = start + match[0].length;
1454
+ decorations.push({
1455
+ from: start,
1456
+ to: end,
1457
+ decoration: Decoration.mark({ class: "text-subdued" })
1458
+ });
1459
+ }
1460
+ }
1461
+ {
1462
+ let match;
1463
+ while ((match = regex.command.exec(text)) !== null) {
1464
+ const start = from + match.index + 2;
1465
+ let end = start + match[0].length - 4;
1466
+ const parts = view.state.doc.sliceString(start, end).split(/\s+/);
1467
+ if (parts.length > 1) {
1468
+ const idx = start + parts[0].length;
1469
+ decorations.push({
1470
+ from: idx,
1471
+ to: end,
1472
+ decoration: Decoration.mark({ class: "text-green-text" })
1473
+ });
1474
+ end = idx;
1475
+ }
1476
+ decorations.push({
1477
+ from: start,
1478
+ to: end,
1479
+ decoration: Decoration.mark({ class: "text-blue-text" })
1480
+ });
1481
+ }
1482
+ }
1483
+ {
1484
+ let match;
1485
+ while ((match = regex.var.exec(text)) !== null) {
1486
+ const start = from + match.index + 2;
1487
+ const end = start + match[0].length - 4;
1488
+ decorations.push({
1489
+ from: start,
1490
+ to: end,
1491
+ decoration: Decoration.mark({ class: "text-green-text" })
1492
+ });
1493
+ }
1494
+ }
1495
+ }
1496
+ decorations.sort((a, b) => a.from - b.from || a.to - b.to);
1497
+ const builder = new RangeSetBuilder();
1498
+ for (const { from, to, decoration } of decorations) builder.add(from, to, decoration);
1499
+ return builder.finish();
1500
+ }
1501
+ }, { decorations: (v) => v.decorations });
1502
+ var DXNWidget = class extends WidgetType {
1503
+ _identifier;
1504
+ constructor(_identifier) {
1505
+ super();
1506
+ this._identifier = _identifier;
1507
+ }
1508
+ ignoreEvent() {
1509
+ return false;
1510
+ }
1511
+ eq(other) {
1512
+ return this._identifier === other._identifier;
1513
+ }
1514
+ toDOM() {
1515
+ const text = this._identifier.split(":").map((part) => {
1516
+ const len = 16;
1517
+ const plen = 4;
1518
+ if (part.length > len) return `[${part.slice(0, plen)}…${part.slice(-4)}]`;
1519
+ return part;
1520
+ }).join(":");
1521
+ return Domino.of("span").classNames(mx$1("font-mono dx-tag--blue", tagPadding)).text(text).root;
1522
+ }
1523
+ };
1524
+ var variables = ["this"];
1525
+ var commands = [
1526
+ "this",
1527
+ "each",
1528
+ "if",
1529
+ "unless",
1530
+ "with"
1531
+ ];
1532
+ /**
1533
+ * Provides completions for Handlebars variables.
1534
+ */
1535
+ function handlebarsCompletions(context) {
1536
+ const match = context.matchBefore(/\{\{[^}]*/);
1537
+ if (!match || match.from === match.to) return null;
1538
+ let type = "variable";
1539
+ let text = match.text.slice(2);
1540
+ let from = match.from + 2;
1541
+ let matches = [];
1542
+ if (text.startsWith("#") || text.startsWith("/")) {
1543
+ const idx = text.lastIndexOf(" ");
1544
+ if (idx !== -1) {
1545
+ type = "variable";
1546
+ matches = variables;
1547
+ text = text.slice(idx + 1);
1548
+ from += idx + 1;
1549
+ } else {
1550
+ type = "command";
1551
+ text = text.slice(1);
1552
+ matches = commands;
1553
+ from += 1;
1554
+ }
1555
+ } else {
1556
+ type = "variable";
1557
+ matches = variables;
1558
+ }
1559
+ const options = matches.filter((name) => name.startsWith(text)).map((name) => ({
1560
+ type,
1561
+ label: name
1562
+ }));
1563
+ return {
1564
+ from,
1565
+ options
1566
+ };
1567
+ }
1568
+ //#endregion
1569
+ //#region src/components/TemplateEditor/extensions/xml-extension.ts
1570
+ /**
1571
+ * XML decorator plugin for CodeMirror.
1572
+ * Decorates XML tags with monospace font using the XML language grammar.
1573
+ */
1574
+ var xmlDecorator = (_ = {}) => {
1575
+ return [xmlDecoratorPlugin];
1576
+ };
1577
+ /**
1578
+ * ViewPlugin that decorates XML tags using syntax tree.
1579
+ */
1580
+ var xmlDecoratorPlugin = ViewPlugin.fromClass(class {
1581
+ decorations;
1582
+ constructor(view) {
1583
+ this.decorations = this.buildDecorations(view);
1584
+ }
1585
+ update(update) {
1586
+ if (update.docChanged || update.viewportChanged) this.decorations = this.buildDecorations(update.view);
1587
+ }
1588
+ buildDecorations(view) {
1589
+ const builder = new RangeSetBuilder();
1590
+ for (const { from, to } of view.visibleRanges) syntaxTree(view.state).iterate({
1591
+ from,
1592
+ to,
1593
+ enter: (node) => {
1594
+ if (node.name === "HTMLTag" || node.name === "OpenTag" || node.name === "CloseTag" || node.name === "SelfClosingTag" || node.name === "Element") builder.add(node.from, node.to, Decoration.mark({ class: "font-mono text-subdued" }));
1595
+ }
1596
+ });
1597
+ return builder.finish();
1598
+ }
1599
+ }, { decorations: (v) => v.decorations });
1600
+ //#endregion
1601
+ //#region src/components/TemplateEditor/TemplateEditor.tsx
1602
+ var TemplateEditor = composable(({ classNames, id, source, lineNumbers = true, ...props }, forwardedRef) => {
1603
+ const { t } = useTranslation(meta.profile.key);
1604
+ const { themeMode } = useThemeContext();
1605
+ const { parentRef } = useTextEditor(() => {
1606
+ const target = source?.target;
1607
+ if (!target) return {};
1608
+ return {
1609
+ initialValue: target.content ?? "",
1610
+ extensions: [
1611
+ createDataExtensions({
1612
+ id,
1613
+ text: Doc.createAccessor(target, ["content"])
1614
+ }),
1615
+ createBasicExtensions({
1616
+ bracketMatching: false,
1617
+ lineNumbers,
1618
+ lineWrapping: true,
1619
+ placeholder: t("template.placeholder")
1620
+ }),
1621
+ createThemeExtensions({ themeMode }),
1622
+ createMarkdownExtensions(),
1623
+ decorateMarkdown(),
1624
+ handlebars(),
1625
+ xmlDecorator(),
1626
+ syntaxHighlighting(defaultHighlightStyle)
1627
+ ].filter(isNonNullable)
1628
+ };
1629
+ }, [
1630
+ themeMode,
1631
+ source?.target,
1632
+ lineNumbers
1633
+ ]);
1634
+ return /* @__PURE__ */ jsx("div", {
1635
+ ...composableProps(props, {
1636
+ role: "none",
1637
+ classNames: ["h-full overflow-hidden", classNames]
1638
+ }),
1639
+ ref: composeRefs(parentRef, forwardedRef)
1640
+ });
1641
+ });
1642
+ //#endregion
1643
+ export { CreateRoutinePanel, CronSpec, CustomSpec, DailySpec, DayOfWeek, Days, FrequencyDefaults, HourlySpec, InstructionsEditor, MAX_MIN_INTERVAL_SECONDS, MinutelySpec, MonthlySpec, RoutineCard, RoutineForm, Schedule, ScheduleKinds, TemplateEditor, TriggerEditor, WeeklySpec, clampSchedule, cronIntervalSeconds, cronToSchedule, describeCron, describeSchedule, fromCron, scheduleIntervalSeconds, scheduleToCron, toCron };
1644
+
1645
+ //# sourceMappingURL=components.mjs.map