@dxos/plugin-routine 0.10.0 → 0.11.1

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
@@ -6,9 +6,9 @@ import * as Effect from 'effect/Effect';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
8
  import { ServiceResolver } from '@dxos/compute';
9
+ import { TriggerDispatcher } from '@dxos/compute-runtime';
9
10
  import { Feed, Obj } from '@dxos/echo';
10
11
  import { EffectEx } from '@dxos/effect';
11
- import { TriggerDispatcher } from '@dxos/functions-runtime';
12
12
  import type { SpaceId } from '@dxos/keys';
13
13
  import { ClientCapabilities, ClientEvents } from '@dxos/plugin-client';
14
14
  import { ClientPlugin, initializeIdentity } from '@dxos/plugin-client/testing';
@@ -30,7 +30,7 @@ const getDispatcher = (harness: Awaited<ReturnType<typeof createComposerTestApp>
30
30
  );
31
31
 
32
32
  describe('TriggerRuntimeController', () => {
33
- test('toggles the per-space TriggerDispatcher as computeEnvironment changes', async ({ expect }) => {
33
+ test('toggles the per-space TriggerDispatcher as triggersDisabled changes', async ({ expect }) => {
34
34
  await using harness = await createComposerTestApp({
35
35
  plugins: [ClientPlugin({ types: [Feed.Feed] }), RoutinePlugin()],
36
36
  });
@@ -51,36 +51,30 @@ describe('TriggerRuntimeController', () => {
51
51
  immediate: true,
52
52
  });
53
53
  try {
54
- // Default `computeEnvironment` is `local`, so the controller should
54
+ // `triggersDisabled` is unset by default, so the controller should
55
55
  // start the dispatcher shortly after the space becomes ready.
56
56
  await expect.poll(() => harness.registry.get(dispatcher.state).enabled, { timeout: 5_000 }).toBe(true);
57
57
 
58
- // `disabled` → dispatcher should stop.
58
+ // `triggersDisabled = true` → dispatcher should stop.
59
59
  Obj.update(personalSpace.properties, (properties) => {
60
- properties.computeEnvironment = 'disabled';
60
+ properties.triggersDisabled = true;
61
61
  });
62
62
  await expect.poll(() => harness.registry.get(dispatcher.state).enabled, { timeout: 5_000 }).toBe(false);
63
63
 
64
- // Back to `local` → dispatcher should start again.
64
+ // Back to enabled → dispatcher should start again.
65
65
  Obj.update(personalSpace.properties, (properties) => {
66
- properties.computeEnvironment = 'local';
66
+ properties.triggersDisabled = false;
67
67
  });
68
68
  await expect.poll(() => harness.registry.get(dispatcher.state).enabled, { timeout: 5_000 }).toBe(true);
69
69
 
70
- // `edge` → dispatcher should stop (triggers run on the edge instead).
71
- Obj.update(personalSpace.properties, (properties) => {
72
- properties.computeEnvironment = 'edge';
73
- });
74
- await expect.poll(() => harness.registry.get(dispatcher.state).enabled, { timeout: 5_000 }).toBe(false);
75
-
76
70
  // The atom subscription should have witnessed every transition.
77
- expect(observedStates).toEqual(expect.arrayContaining([true, false, true, false]));
71
+ expect(observedStates).toEqual(expect.arrayContaining([true, false, true]));
78
72
  } finally {
79
73
  unsubscribe();
80
74
  }
81
75
  });
82
76
 
83
- test('does not re-issue start when computeEnvironment is reasserted to the same value', async ({ expect }) => {
77
+ test('does not re-issue start when triggersDisabled is reasserted to the same value', async ({ expect }) => {
84
78
  await using harness = await createComposerTestApp({
85
79
  plugins: [ClientPlugin({ types: [Feed.Feed] }), RoutinePlugin()],
86
80
  });
@@ -94,11 +88,11 @@ describe('TriggerRuntimeController', () => {
94
88
 
95
89
  await expect.poll(() => harness.registry.get(dispatcher.state).enabled, { timeout: 5_000 }).toBe(true);
96
90
 
97
- // Writing the same `local` value should be a no-op: the controller
98
- // dedupes via its `lastEnvironment` tracker so the dispatcher stays
91
+ // Writing the same enabled state should be a no-op: the controller
92
+ // dedupes via its `lastDisabled` tracker so the dispatcher stays
99
93
  // running without an intervening stop/start flicker.
100
94
  Obj.update(personalSpace.properties, (properties) => {
101
- properties.computeEnvironment = 'local';
95
+ properties.triggersDisabled = false;
102
96
  });
103
97
  // Give any spurious transition a chance to land before we check.
104
98
  await new Promise((resolve) => setTimeout(resolve, 100));
@@ -6,10 +6,9 @@ import * as Effect from 'effect/Effect';
6
6
  import * as Fiber from 'effect/Fiber';
7
7
 
8
8
  import { Capabilities, Capability } from '@dxos/app-framework';
9
- import { type ComputeEnvironment } from '@dxos/client-protocol';
10
9
  import { ServiceResolver } from '@dxos/compute';
10
+ import { TriggerDispatcher } from '@dxos/compute-runtime';
11
11
  import { Obj } from '@dxos/echo';
12
- import { TriggerDispatcher } from '@dxos/functions-runtime';
13
12
  import { type SpaceId } from '@dxos/keys';
14
13
  import { log } from '@dxos/log';
15
14
  import { ClientCapabilities } from '@dxos/plugin-client';
@@ -18,30 +17,28 @@ import { type Space } from '@dxos/react-client/echo';
18
17
  //
19
18
  // Capability Module
20
19
  //
21
- // Watches `space.properties.computeEnvironment` for every space and toggles
20
+ // Watches `space.properties.triggersDisabled` for every space and toggles
22
21
  // the per-space {@link TriggerDispatcher} accordingly:
23
22
  //
24
- // - `local` → `dispatcher.start()`
25
- // - `edge` / `disabled` → `dispatcher.stop()`
23
+ // - disabled (`true`) → `dispatcher.stop()`
24
+ // - enabled (unset/`false`) → `dispatcher.start()`
26
25
  //
27
- // Replaces the in-line watcher that used to live inside the removed
28
- // `compute-runtime.ts` per-space layer. The dispatcher itself is now
29
- // contributed unconditionally via `TriggerDispatcherSpec` in `layer-specs.ts`,
30
- // so this capability is only responsible for driving its lifecycle.
26
+ // Per-trigger local/edge routing is handled by the trigger's `remote` flag
27
+ // (the dispatcher skips remote triggers); this space-wide flag is only the
28
+ // kill-switch for local execution. The dispatcher itself is contributed
29
+ // unconditionally via `TriggerDispatcherSpec` in `layer-specs.ts`, so this
30
+ // capability is only responsible for driving its lifecycle.
31
31
  //
32
32
 
33
- /** Trigger execution location the dispatcher should run locally. */
34
- const LOCAL_ENVIRONMENT: ComputeEnvironment = 'local';
35
-
36
33
  export default Capability.makeModule(
37
34
  Effect.fnUntraced(function* () {
38
35
  const client = yield* Capability.get(ClientCapabilities.Client);
39
36
  const runtime = yield* Capability.get(Capabilities.ProcessManagerRuntime);
40
37
 
41
- /** Per-space property-subscription unsubscribe, last-seen environment, and in-flight transition fiber. */
38
+ /** Per-space property-subscription unsubscribe, last-seen disabled state, and in-flight transition fiber. */
42
39
  type Tracker = {
43
40
  unsubscribe: () => void;
44
- lastEnvironment?: ComputeEnvironment;
41
+ lastDisabled?: boolean;
45
42
  inFlight?: Fiber.RuntimeFiber<unknown, unknown>;
46
43
  };
47
44
  const trackers = new Map<SpaceId, Tracker>();
@@ -49,31 +46,31 @@ export default Capability.makeModule(
49
46
  /**
50
47
  * Resolve the per-space `TriggerDispatcher` from the process-manager
51
48
  * runtime and invoke `start()` / `stop()` according to the requested
52
- * environment. Returns a fiber so the caller can cancel a pending
49
+ * disabled state. Returns a fiber so the caller can cancel a pending
53
50
  * transition when a new one supersedes it.
54
51
  */
55
- const transition = (spaceId: SpaceId, environment: ComputeEnvironment) =>
52
+ const transition = (spaceId: SpaceId, disabled: boolean) =>
56
53
  runtime.runFork(
57
54
  Effect.gen(function* () {
58
55
  const dispatcher = yield* TriggerDispatcher;
59
- yield* environment === LOCAL_ENVIRONMENT ? dispatcher.start() : dispatcher.stop();
56
+ yield* disabled ? dispatcher.stop() : dispatcher.start();
60
57
  }).pipe(
61
58
  Effect.provide(ServiceResolver.provide({ space: spaceId }, TriggerDispatcher)),
62
59
  Effect.tapErrorCause((cause) =>
63
- Effect.sync(() => log.warn('trigger dispatcher transition failed', { spaceId, environment, cause })),
60
+ Effect.sync(() => log.warn('trigger dispatcher transition failed', { spaceId, disabled, cause })),
64
61
  ),
65
62
  ),
66
63
  );
67
64
 
68
- const apply = (tracker: Tracker, spaceId: SpaceId, environment: ComputeEnvironment): void => {
69
- if (tracker.lastEnvironment === environment) {
65
+ const apply = (tracker: Tracker, spaceId: SpaceId, disabled: boolean): void => {
66
+ if (tracker.lastDisabled === disabled) {
70
67
  return;
71
68
  }
72
- tracker.lastEnvironment = environment;
69
+ tracker.lastDisabled = disabled;
73
70
  if (tracker.inFlight) {
74
71
  runtime.runFork(Fiber.interrupt(tracker.inFlight));
75
72
  }
76
- tracker.inFlight = transition(spaceId, environment);
73
+ tracker.inFlight = transition(spaceId, disabled);
77
74
  };
78
75
 
79
76
  const install = (space: Space): void => {
@@ -94,9 +91,9 @@ export default Capability.makeModule(
94
91
  if (trackers.get(space.id) !== tracker) {
95
92
  return;
96
93
  }
97
- const readEnvironment = (): ComputeEnvironment => space.properties.computeEnvironment ?? LOCAL_ENVIRONMENT;
98
- tracker.unsubscribe = Obj.subscribe(space.properties, () => apply(tracker, space.id, readEnvironment()));
99
- apply(tracker, space.id, readEnvironment());
94
+ const readDisabled = (): boolean => space.properties.triggersDisabled ?? false;
95
+ tracker.unsubscribe = Obj.subscribe(space.properties, () => apply(tracker, space.id, readDisabled()));
96
+ apply(tracker, space.id, readDisabled());
100
97
  })
101
98
  .catch((err) => log.catch(err));
102
99
  };
@@ -20,7 +20,7 @@ import { EID } from '@dxos/keys';
20
20
  import { Enabled, Feed, Input } from '../options';
21
21
  import { printTrigger, promptForSchemaInput, selectFeed, selectFunction } from '../util';
22
22
 
23
- export const queue = Command.make(
23
+ export const feed = Command.make(
24
24
  'feed',
25
25
  {
26
26
  spaceId: Common.spaceId.pipe(Options.optional),
@@ -4,11 +4,11 @@
4
4
 
5
5
  import * as Command from '@effect/cli/Command';
6
6
 
7
- import { queue } from './queue';
7
+ import { feed } from './feed';
8
8
  import { subscription } from './subscription';
9
9
  import { timer } from './timer';
10
10
 
11
11
  export const create = Command.make('create').pipe(
12
12
  Command.withDescription('Create a trigger.'),
13
- Command.withSubcommands([subscription, timer, queue]),
13
+ Command.withSubcommands([subscription, timer, feed]),
14
14
  );
@@ -19,7 +19,7 @@ import { EID, type EntityId } from '@dxos/keys';
19
19
  import { Enabled, Feed, Input, TriggerId } from '../options';
20
20
  import { printTrigger, promptForSchemaInput, selectFeed, selectFunction, selectTrigger } from '../util';
21
21
 
22
- export const queue = Command.make(
22
+ export const feed = Command.make(
23
23
  'feed',
24
24
  {
25
25
  spaceId: Common.spaceId.pipe(Options.optional),
@@ -4,11 +4,11 @@
4
4
 
5
5
  import * as Command from '@effect/cli/Command';
6
6
 
7
- import { queue } from './queue';
7
+ import { feed } from './feed';
8
8
  import { subscription } from './subscription';
9
9
  import { timer } from './timer';
10
10
 
11
11
  export const update = Command.make('update').pipe(
12
12
  Command.withDescription('Update a trigger.'),
13
- Command.withSubcommands([subscription, timer, queue]),
13
+ Command.withSubcommands([subscription, timer, feed]),
14
14
  );
@@ -13,8 +13,7 @@ import * as SchemaAST from 'effect/SchemaAST';
13
13
 
14
14
  import { FormBuilder } from '@dxos/cli-util';
15
15
  import { Operation, Trigger } from '@dxos/compute';
16
- // eslint-disable-next-line unused-imports/no-unused-imports
17
- import { Annotation, Database, Entity, Feed, Filter, Obj, Query, type QueryAST, Ref, Scope, Type } from '@dxos/echo';
16
+ import { Annotation, Database, Entity, Feed, Filter, Obj, Query, Ref, Scope, Type } from '@dxos/echo';
18
17
  import { SchemaEx } from '@dxos/effect';
19
18
  import { DXN } from '@dxos/keys';
20
19
  import { FeedAnnotation } from '@dxos/schema';
@@ -7,7 +7,8 @@ import React from 'react';
7
7
 
8
8
  import { Instructions, Skill } from '@dxos/compute';
9
9
  import { Filter, Ref } from '@dxos/echo';
10
- import { type Space, useQuery } from '@dxos/react-client/echo';
10
+ import { useQuery } from '@dxos/echo-react';
11
+ import { type Space } from '@dxos/react-client/echo';
11
12
  import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
12
13
  import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
13
14
  import { Text } from '@dxos/schema';
@@ -49,7 +50,7 @@ export default meta;
49
50
 
50
51
  type Story = StoryObj<typeof meta>;
51
52
 
52
- /** A routine with no skills or context objects: the form shows empty add affordances. */
53
+ /** A routine with no skills: the form shows an empty add affordance. */
53
54
  export const Default: Story = {
54
55
  decorators: [
55
56
  withSeededSpace((space) => {
@@ -58,12 +59,12 @@ export const Default: Story = {
58
59
  ],
59
60
  };
60
61
 
61
- /** A routine seeded with a context object: the Objects field renders the populated ref slot. */
62
- export const WithObject: Story = {
62
+ /** A routine seeded with a skill: the Skills field renders the populated ref slot. */
63
+ export const WithSkill: Story = {
63
64
  decorators: [
64
65
  withSeededSpace((space) => {
65
- const subject = space.db.add(Text.make({ content: 'Meeting notes' }));
66
- space.db.add(Instructions.make({ name: 'Summarize notes', objects: [Ref.make(subject)] }));
66
+ const skill = space.db.add(Skill.make({ key: 'org.dxos.test.summarize', name: 'Summarize' }));
67
+ space.db.add(Instructions.make({ name: 'Summarize notes', skills: [Ref.make(skill)] }));
67
68
  }),
68
69
  ],
69
70
  };
@@ -12,50 +12,62 @@ import { Form } from '@dxos/react-ui-form';
12
12
 
13
13
  const INSTRUCTIONS_SCHEMA = Type.getSchema(Instructions.Instructions);
14
14
 
15
- // Owned-routine action fields surfaced for editing — the prompt text, the agent's `skills`,
16
- // and the context `objects` bound to its session at run. All live on the Instructions schema,
17
- // so a single form edits them together.
18
- const INSTRUCTIONS_FIELDS = new Set(['text', 'skills', 'objects']);
15
+ // Owned-routine action fields surfaced by default — the prompt text and the agent's `skills`. The
16
+ // context `objects` are excluded here so a routine form doesn't show a second, divergent list beside
17
+ // its owning subject; a surface that owns the context concern (e.g. a project's Context section)
18
+ // opts in via `fields`.
19
+ const DEFAULT_FIELDS: readonly string[] = ['text', 'skills'];
19
20
 
20
21
  export type InstructionsEditorProps = {
21
- db?: Database.Database;
22
+ db?: Database.Database; // TODO(burdon): Should not be optional if instructions are not.
22
23
  instructions: Instructions.Instructions;
23
24
  readonly?: boolean;
25
+ /** Instructions schema fields rendered AND written back; others are left untouched. */
26
+ fields?: readonly string[];
24
27
  };
25
28
 
26
29
  /**
27
- * Sub-form: edits the owned Instructions in place — its `text` (Markdown), `skills`, and the
28
- * context `objects` bound to its session at run, all fields of the Instructions schema. A bare Form.Root +
29
- * FieldSet (no Viewport) keeps these fields left-aligned with the sibling general/action forms; the
30
- * rendered fields are written back so selections persist to the instructions.
30
+ * Sub-form: edits the owned Instructions in place — by default its `text` (Markdown) and `skills`,
31
+ * both fields of the Instructions schema. A bare Form.Root + FieldSet (no Viewport) keeps these
32
+ * fields left-aligned with the sibling general/action forms; only the rendered fields are written
33
+ * back so a partial editor never clobbers the rest of the object.
31
34
  */
32
- export const InstructionsEditor = ({ db: dbProp, instructions, readonly }: InstructionsEditorProps) => {
35
+ export const InstructionsEditor = ({
36
+ db: dbProp,
37
+ instructions,
38
+ readonly,
39
+ fields = DEFAULT_FIELDS,
40
+ }: InstructionsEditorProps) => {
33
41
  // A draft routine is not yet attached to a database, so fall back to the explicit `db` for ref queries.
34
42
  const db = dbProp ?? Obj.getDatabase(instructions);
35
43
 
36
- // `objects` is optional; normalize to an array so the ref-array field renders its add affordance.
37
44
  const defaultValues = useMemo<Partial<Instructions.Instructions>>(
38
- () => ({ ...Obj.getSnapshot(instructions), objects: instructions.objects ? [...instructions.objects] : [] }),
45
+ () => ({ ...Obj.getSnapshot(instructions) }),
39
46
  [instructions],
40
47
  );
41
48
 
49
+ const fieldSet = useMemo(() => new Set(fields), [fields]);
42
50
  const handleValuesChanged = useCallback(
43
51
  (values: Partial<Instructions.Instructions>, { isValid }: { isValid: boolean }) => {
44
- // Skip while invalid (e.g. an empty ref slot just added by a skills/objects array field) so a
45
- // partial selection isn't persisted; the write lands once the slot is filled.
52
+ // Skip while invalid (e.g. an empty ref slot just added by the skills array field) so a partial
53
+ // selection isn't persisted; the write lands once the slot is filled.
46
54
  if (!isValid) {
47
55
  return;
48
56
  }
49
57
 
50
58
  Obj.update(instructions, (instructions) => {
51
- if (values.text) {
59
+ if (fieldSet.has('text') && values.text) {
52
60
  instructions.text = values.text;
53
61
  }
54
- instructions.skills = [...(values.skills ?? [])];
55
- instructions.objects = [...(values.objects ?? [])];
62
+ if (fieldSet.has('skills')) {
63
+ instructions.skills = [...(values.skills ?? [])];
64
+ }
65
+ if (fieldSet.has('objects')) {
66
+ instructions.objects = [...(values.objects ?? [])];
67
+ }
56
68
  });
57
69
  },
58
- [instructions],
70
+ [instructions, fieldSet],
59
71
  );
60
72
 
61
73
  return (
@@ -68,7 +80,7 @@ export const InstructionsEditor = ({ db: dbProp, instructions, readonly }: Instr
68
80
  getOptions={getRefOptions}
69
81
  onValuesChanged={handleValuesChanged}
70
82
  >
71
- <Form.FieldSet filter={(props) => props.filter((prop) => INSTRUCTIONS_FIELDS.has(prop.name.toString()))} />
83
+ <Form.FieldSet filter={(props) => props.filter((prop) => fieldSet.has(prop.name.toString()))} />
72
84
  </Form.Root>
73
85
  );
74
86
  };
@@ -0,0 +1,95 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React from 'react';
7
+
8
+ import { Instructions, Routine, Trigger } from '@dxos/compute';
9
+ import { Filter, Query } from '@dxos/echo';
10
+ import { useQuery } from '@dxos/echo-react';
11
+ import { type Space } from '@dxos/react-client/echo';
12
+ import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
13
+ import { Card } from '@dxos/react-ui';
14
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
15
+ import { Text } from '@dxos/schema';
16
+
17
+ import { translations } from '#translations';
18
+
19
+ import { makeRoutine } from '../../util';
20
+ import { RoutineCard } from './RoutineCard';
21
+
22
+ const types = [Routine.Routine, Instructions.Instructions, Trigger.Trigger, Text.Text];
23
+
24
+ const DefaultStory = () => {
25
+ const { space } = useClientStory();
26
+ const [routine] = useQuery(space?.db, Filter.type(Routine.Routine));
27
+ if (!space || !routine) {
28
+ return <Loading />;
29
+ }
30
+
31
+ // The surface host supplies Card.Root and the header; RoutineCard emits only the body.
32
+ return (
33
+ <Card.Root fullWidth>
34
+ <Card.Header>
35
+ <Card.Title>{routine.name ?? 'Untitled'}</Card.Title>
36
+ </Card.Header>
37
+ <RoutineCard subject={routine} />
38
+ </Card.Root>
39
+ );
40
+ };
41
+
42
+ const withSeededRoutine = ({ name, spec, enabled }: { name?: string; spec?: Trigger.Spec; enabled?: boolean } = {}) =>
43
+ withClientProvider({
44
+ createIdentity: true,
45
+ createSpace: true,
46
+ types,
47
+ onCreateSpace: async ({ space }: { space: Space }) => {
48
+ space.db.add(
49
+ makeRoutine({
50
+ name,
51
+ instructions: Instructions.make({ text: 'Summarize the day.' }),
52
+ trigger: Trigger.make({ spec, enabled }),
53
+ }),
54
+ );
55
+ },
56
+ });
57
+
58
+ const meta = {
59
+ title: 'plugins/plugin-routine/components/RoutineCard',
60
+ render: DefaultStory,
61
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
62
+ parameters: {
63
+ translations,
64
+ },
65
+ } satisfies Meta<typeof DefaultStory>;
66
+
67
+ export default meta;
68
+
69
+ type Story = StoryObj<typeof meta>;
70
+
71
+ /** An active scheduled routine: the schedule summary, with the green check marking it switched on. */
72
+ export const Default: Story = {
73
+ decorators: [withSeededRoutine({ name: 'Daily Digest', spec: Trigger.specTimer('0 9 * * *'), enabled: true })],
74
+ };
75
+
76
+ /** The same routine switched off: same summary, no check. */
77
+ export const Inactive: Story = {
78
+ decorators: [withSeededRoutine({ name: 'Daily Digest', spec: Trigger.specTimer('0 9 * * *') })],
79
+ };
80
+
81
+ /** A non-timer trigger has no parameters worth summarizing, so the kind description stands in. */
82
+ export const QueryTrigger: Story = {
83
+ decorators: [
84
+ withSeededRoutine({
85
+ name: 'Watch tasks',
86
+ spec: Trigger.specSubscription(Query.select(Filter.type(Text.Text))),
87
+ enabled: true,
88
+ }),
89
+ ],
90
+ };
91
+
92
+ /** A freshly created (blank-template) routine: the body prompts for a trigger. */
93
+ export const NoTrigger: Story = {
94
+ decorators: [withSeededRoutine()],
95
+ };
@@ -0,0 +1,60 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { type AppSurface } from '@dxos/app-toolkit/ui';
8
+ import { type Routine, type Trigger } from '@dxos/compute';
9
+ import { useObject } from '@dxos/echo-react';
10
+ import { Card, Icon, useTranslation } from '@dxos/react-ui';
11
+
12
+ import { meta } from '#meta';
13
+
14
+ import { cronToSchedule, describeSchedule } from '../Schedule';
15
+
16
+ export type RoutineCardProps = AppSurface.ObjectCardProps<Routine.Routine>;
17
+
18
+ /**
19
+ * Compact preview of a {@link Routine.Routine}: when it runs. Rendered into the
20
+ * `AppSurface.CardContent` slot — Card.Root is supplied by the surface host (the project article's
21
+ * gallery, popovers, related-objects), so this emits Card.Body only. Without it a routine falls back
22
+ * to the generic form preview, which renders its `spec`/`triggers` internals rather than a summary.
23
+ */
24
+ export const RoutineCard = ({ subject }: RoutineCardProps) => {
25
+ const { t } = useTranslation(meta.profile.key);
26
+ const [routine] = useObject(subject);
27
+ // MVP enforces at most one trigger; the summary describes it.
28
+ const [trigger] = useObject(routine.triggers.at(0));
29
+
30
+ // Active means the same thing as in the routines list: a trigger exists and is switched on.
31
+ const active = trigger?.enabled === true;
32
+
33
+ return (
34
+ <Card.Body>
35
+ <Card.Row>
36
+ {/* The gutter is reserved either way so the summary stays aligned across cards. */}
37
+ <Card.Block>{active && <Icon icon='ph--check-circle--regular' classNames='text-green-text' />}</Card.Block>
38
+ <Card.Text variant='description' classNames='line-clamp-2'>
39
+ {describeTrigger(trigger?.spec, t)}
40
+ </Card.Text>
41
+ </Card.Row>
42
+ </Card.Body>
43
+ );
44
+ };
45
+
46
+ RoutineCard.displayName = 'RoutineCard';
47
+
48
+ /**
49
+ * The same sentence the trigger editor shows above the schedule picker. Non-timer kinds have no
50
+ * parameters worth summarizing, so they reuse the kind description from the trigger-kind picker.
51
+ */
52
+ const describeTrigger = (spec: Trigger.Spec | undefined, t: (key: string) => string): string => {
53
+ if (!spec) {
54
+ return t('add-trigger-first.message');
55
+ }
56
+
57
+ return spec.kind === 'timer'
58
+ ? describeSchedule(cronToSchedule(spec.cron))
59
+ : t(`trigger-kind.${spec.kind}.description`);
60
+ };
@@ -2,4 +2,4 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- export * from './MasterDetail';
5
+ export * from './RoutineCard';