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