@dxos/plugin-automation 0.8.2-main.f11618f → 0.8.2-staging.42af850

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 (165) hide show
  1. package/dist/lib/browser/AutomationContainer-HQK7FTN6.mjs +40 -0
  2. package/dist/lib/{node-esm/AutomationContainer-22PUFPSE.mjs.map → browser/AutomationContainer-HQK7FTN6.mjs.map} +1 -1
  3. package/dist/lib/browser/AutomationPanel-GU37N5LO.mjs +11 -0
  4. package/dist/lib/browser/FunctionsContainer-B7RDWVMX.mjs +39 -0
  5. package/dist/lib/{node-esm/FunctionsContainer-XG5WVAN3.mjs.map → browser/FunctionsContainer-B7RDWVMX.mjs.map} +1 -1
  6. package/dist/lib/browser/{FunctionsPanel-JJPLIAJW.mjs → FunctionsPanel-LCCPDIT6.mjs} +3 -3
  7. package/dist/lib/browser/{app-graph-builder-ND64CHOM.mjs → app-graph-builder-BYECL42X.mjs} +16 -17
  8. package/dist/lib/browser/app-graph-builder-BYECL42X.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-4E2KPMLB.mjs +39 -0
  10. package/dist/lib/browser/chunk-4E2KPMLB.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-4QTXMPBC.mjs +229 -0
  12. package/dist/lib/browser/chunk-4QTXMPBC.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-D2ESAYQD.mjs +149 -0
  14. package/dist/lib/browser/chunk-D2ESAYQD.mjs.map +7 -0
  15. package/dist/lib/browser/{chunk-QJPKWYTL.mjs → chunk-ELQ2FX5G.mjs} +5 -5
  16. package/dist/lib/browser/{chunk-WKKQV4PC.mjs → chunk-IHAKPP5A.mjs} +2 -2
  17. package/dist/lib/browser/{chunk-WKKQV4PC.mjs.map → chunk-IHAKPP5A.mjs.map} +1 -1
  18. package/dist/lib/browser/chunk-ZTRYR6RJ.mjs +94 -0
  19. package/dist/lib/browser/chunk-ZTRYR6RJ.mjs.map +7 -0
  20. package/dist/lib/browser/index.mjs +7 -7
  21. package/dist/lib/browser/index.mjs.map +1 -1
  22. package/dist/lib/browser/{intent-resolver-SNIAQ7V5.mjs → intent-resolver-ZRBBYZUX.mjs} +13 -14
  23. package/dist/lib/browser/intent-resolver-ZRBBYZUX.mjs.map +7 -0
  24. package/dist/lib/browser/meta.json +1 -1
  25. package/dist/lib/browser/{react-surface-L22QIANU.mjs → react-surface-VKO6PA2P.mjs} +5 -5
  26. package/dist/lib/browser/{react-surface-L22QIANU.mjs.map → react-surface-VKO6PA2P.mjs.map} +1 -1
  27. package/dist/lib/browser/types.mjs +2 -2
  28. package/dist/lib/node/{AutomationContainer-E5I76FPP.cjs → AutomationContainer-5J7LJK7L.cjs} +26 -20
  29. package/dist/lib/node/{AutomationContainer-E5I76FPP.cjs.map → AutomationContainer-5J7LJK7L.cjs.map} +1 -1
  30. package/dist/lib/node/{AutomationPanel-YLXAFJDP.cjs → AutomationPanel-NPDBUQ7D.cjs} +9 -9
  31. package/dist/lib/node/{AutomationPanel-YLXAFJDP.cjs.map → AutomationPanel-NPDBUQ7D.cjs.map} +2 -2
  32. package/dist/lib/node/{FunctionsContainer-3HCURMEB.cjs → FunctionsContainer-LNLDZUZ6.cjs} +25 -19
  33. package/dist/lib/node/{FunctionsContainer-3HCURMEB.cjs.map → FunctionsContainer-LNLDZUZ6.cjs.map} +1 -1
  34. package/dist/lib/node/{FunctionsPanel-SYIZHPGU.cjs → FunctionsPanel-7AOXIQMA.cjs} +8 -8
  35. package/dist/lib/node/FunctionsPanel-7AOXIQMA.cjs.map +7 -0
  36. package/dist/lib/node/{app-graph-builder-TVFR6RXO.cjs → app-graph-builder-DUKR2BRB.cjs} +28 -29
  37. package/dist/lib/node/app-graph-builder-DUKR2BRB.cjs.map +7 -0
  38. package/dist/lib/node/{chunk-7GXNXMSM.cjs → chunk-3EF7MLFX.cjs} +5 -5
  39. package/dist/lib/node/{chunk-7GXNXMSM.cjs.map → chunk-3EF7MLFX.cjs.map} +1 -1
  40. package/dist/lib/node/chunk-4O627QZU.cjs +175 -0
  41. package/dist/lib/node/chunk-4O627QZU.cjs.map +7 -0
  42. package/dist/lib/node/{chunk-L5TWLPGA.cjs → chunk-DOLMQUQ5.cjs} +8 -8
  43. package/dist/lib/node/{chunk-PSIJDHAX.cjs → chunk-GIIVTK4O.cjs} +22 -22
  44. package/dist/lib/node/chunk-GIIVTK4O.cjs.map +7 -0
  45. package/dist/lib/node/chunk-O42NQYQT.cjs +252 -0
  46. package/dist/lib/node/chunk-O42NQYQT.cjs.map +7 -0
  47. package/dist/lib/node/chunk-WXQAVUBJ.cjs +122 -0
  48. package/dist/lib/node/chunk-WXQAVUBJ.cjs.map +7 -0
  49. package/dist/lib/node/index.cjs +23 -23
  50. package/dist/lib/node/index.cjs.map +2 -2
  51. package/dist/lib/node/{intent-resolver-A44BNFEG.cjs → intent-resolver-JC4Q4TYU.cjs} +18 -19
  52. package/dist/lib/node/intent-resolver-JC4Q4TYU.cjs.map +7 -0
  53. package/dist/lib/node/meta.json +1 -1
  54. package/dist/lib/node/{react-surface-PCZCHIET.cjs → react-surface-HB3MYTCK.cjs} +17 -17
  55. package/dist/lib/node/react-surface-HB3MYTCK.cjs.map +7 -0
  56. package/dist/lib/node/types.cjs +3 -3
  57. package/dist/lib/node/types.cjs.map +1 -1
  58. package/dist/lib/node-esm/AutomationContainer-OJGH76X2.mjs +41 -0
  59. package/dist/lib/{browser/AutomationContainer-KEQ5RNIW.mjs.map → node-esm/AutomationContainer-OJGH76X2.mjs.map} +1 -1
  60. package/dist/lib/node-esm/{AutomationPanel-6UXIAJVS.mjs → AutomationPanel-HIWEJUWL.mjs} +4 -4
  61. package/dist/lib/node-esm/FunctionsContainer-PPR6XNNR.mjs +40 -0
  62. package/dist/lib/{browser/FunctionsContainer-STXBW4CX.mjs.map → node-esm/FunctionsContainer-PPR6XNNR.mjs.map} +1 -1
  63. package/dist/lib/node-esm/{FunctionsPanel-J3QGUESH.mjs → FunctionsPanel-SBXKWTHR.mjs} +3 -3
  64. package/dist/lib/node-esm/{app-graph-builder-NYLOXWVV.mjs → app-graph-builder-UAXHKKGW.mjs} +16 -17
  65. package/dist/lib/node-esm/app-graph-builder-UAXHKKGW.mjs.map +7 -0
  66. package/dist/lib/node-esm/chunk-5IAHBEHR.mjs +95 -0
  67. package/dist/lib/node-esm/chunk-5IAHBEHR.mjs.map +7 -0
  68. package/dist/lib/node-esm/chunk-6JOJ2NN4.mjs +40 -0
  69. package/dist/lib/node-esm/chunk-6JOJ2NN4.mjs.map +7 -0
  70. package/dist/lib/node-esm/chunk-D5HK4XLC.mjs +230 -0
  71. package/dist/lib/node-esm/chunk-D5HK4XLC.mjs.map +7 -0
  72. package/dist/lib/node-esm/{chunk-DZ44LGYT.mjs → chunk-HCCLRNMJ.mjs} +2 -2
  73. package/dist/lib/node-esm/{chunk-DZ44LGYT.mjs.map → chunk-HCCLRNMJ.mjs.map} +1 -1
  74. package/dist/lib/node-esm/chunk-P2FKMPRE.mjs +150 -0
  75. package/dist/lib/node-esm/chunk-P2FKMPRE.mjs.map +7 -0
  76. package/dist/lib/node-esm/{chunk-TMMB5ETD.mjs → chunk-Z7VAQDEE.mjs} +5 -5
  77. package/dist/lib/node-esm/index.mjs +7 -7
  78. package/dist/lib/node-esm/index.mjs.map +1 -1
  79. package/dist/lib/node-esm/{intent-resolver-JFLTVJ7D.mjs → intent-resolver-KRCXJEDR.mjs} +13 -14
  80. package/dist/lib/node-esm/intent-resolver-KRCXJEDR.mjs.map +7 -0
  81. package/dist/lib/node-esm/meta.json +1 -1
  82. package/dist/lib/node-esm/{react-surface-VSO4NWC6.mjs → react-surface-TRKCIZAB.mjs} +5 -5
  83. package/dist/lib/node-esm/{react-surface-VSO4NWC6.mjs.map → react-surface-TRKCIZAB.mjs.map} +1 -1
  84. package/dist/lib/node-esm/types.mjs +2 -2
  85. package/dist/types/src/capabilities/app-graph-builder.d.ts +2 -179
  86. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  87. package/dist/types/src/capabilities/index.d.ts +2 -178
  88. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  89. package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
  90. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  91. package/dist/types/src/components/AutomationContainer.d.ts.map +1 -1
  92. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +1 -1
  93. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +1 -1
  94. package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts.map +1 -1
  95. package/dist/types/src/components/FunctionsContainer.d.ts.map +1 -1
  96. package/dist/types/src/components/FunctionsPanel/FunctionsPanel.d.ts.map +1 -1
  97. package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts +12 -0
  98. package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts.map +1 -0
  99. package/dist/types/src/components/TriggerEditor/SpecSelector.d.ts +5 -0
  100. package/dist/types/src/components/TriggerEditor/SpecSelector.d.ts.map +1 -0
  101. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +1 -1
  102. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
  103. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -1
  104. package/dist/types/src/testing/test-functions.d.ts.map +1 -1
  105. package/dist/types/src/types.d.ts +15 -15
  106. package/dist/types/src/types.d.ts.map +1 -1
  107. package/dist/types/tsconfig.tsbuildinfo +1 -1
  108. package/package.json +33 -25
  109. package/src/AutomationPlugin.tsx +1 -1
  110. package/src/capabilities/app-graph-builder.ts +65 -41
  111. package/src/capabilities/intent-resolver.ts +10 -13
  112. package/src/capabilities/react-surface.tsx +1 -1
  113. package/src/components/AutomationPanel/AutomationPanel.stories.tsx +4 -3
  114. package/src/components/AutomationPanel/AutomationPanel.tsx +25 -20
  115. package/src/components/FunctionsPanel/FunctionsPanel.tsx +5 -5
  116. package/src/components/TriggerEditor/FunctionInputEditor.tsx +77 -0
  117. package/src/components/TriggerEditor/SpecSelector.tsx +59 -0
  118. package/src/components/TriggerEditor/TriggerEditor.stories.tsx +17 -8
  119. package/src/components/TriggerEditor/TriggerEditor.tsx +64 -102
  120. package/src/meta.ts +1 -1
  121. package/src/testing/test-functions.ts +23 -9
  122. package/src/types.ts +11 -10
  123. package/dist/lib/browser/AutomationContainer-KEQ5RNIW.mjs +0 -34
  124. package/dist/lib/browser/AutomationPanel-G3OB6ELR.mjs +0 -11
  125. package/dist/lib/browser/FunctionsContainer-STXBW4CX.mjs +0 -33
  126. package/dist/lib/browser/app-graph-builder-ND64CHOM.mjs.map +0 -7
  127. package/dist/lib/browser/chunk-65VL4EYS.mjs +0 -88
  128. package/dist/lib/browser/chunk-65VL4EYS.mjs.map +0 -7
  129. package/dist/lib/browser/chunk-FALBBJNO.mjs +0 -138
  130. package/dist/lib/browser/chunk-FALBBJNO.mjs.map +0 -7
  131. package/dist/lib/browser/chunk-FCLWFVFX.mjs +0 -39
  132. package/dist/lib/browser/chunk-FCLWFVFX.mjs.map +0 -7
  133. package/dist/lib/browser/chunk-NGG4ICAQ.mjs +0 -140
  134. package/dist/lib/browser/chunk-NGG4ICAQ.mjs.map +0 -7
  135. package/dist/lib/browser/intent-resolver-SNIAQ7V5.mjs.map +0 -7
  136. package/dist/lib/node/FunctionsPanel-SYIZHPGU.cjs.map +0 -7
  137. package/dist/lib/node/app-graph-builder-TVFR6RXO.cjs.map +0 -7
  138. package/dist/lib/node/chunk-BSK5SHTR.cjs +0 -116
  139. package/dist/lib/node/chunk-BSK5SHTR.cjs.map +0 -7
  140. package/dist/lib/node/chunk-FTEDH5Q6.cjs +0 -167
  141. package/dist/lib/node/chunk-FTEDH5Q6.cjs.map +0 -7
  142. package/dist/lib/node/chunk-PSIJDHAX.cjs.map +0 -7
  143. package/dist/lib/node/chunk-SRXHHBDE.cjs +0 -166
  144. package/dist/lib/node/chunk-SRXHHBDE.cjs.map +0 -7
  145. package/dist/lib/node/intent-resolver-A44BNFEG.cjs.map +0 -7
  146. package/dist/lib/node/react-surface-PCZCHIET.cjs.map +0 -7
  147. package/dist/lib/node-esm/AutomationContainer-22PUFPSE.mjs +0 -35
  148. package/dist/lib/node-esm/FunctionsContainer-XG5WVAN3.mjs +0 -34
  149. package/dist/lib/node-esm/app-graph-builder-NYLOXWVV.mjs.map +0 -7
  150. package/dist/lib/node-esm/chunk-4UPGANGV.mjs +0 -89
  151. package/dist/lib/node-esm/chunk-4UPGANGV.mjs.map +0 -7
  152. package/dist/lib/node-esm/chunk-HMYAQLGF.mjs +0 -141
  153. package/dist/lib/node-esm/chunk-HMYAQLGF.mjs.map +0 -7
  154. package/dist/lib/node-esm/chunk-M4QXMIIB.mjs +0 -139
  155. package/dist/lib/node-esm/chunk-M4QXMIIB.mjs.map +0 -7
  156. package/dist/lib/node-esm/chunk-YYBCQXB2.mjs +0 -40
  157. package/dist/lib/node-esm/chunk-YYBCQXB2.mjs.map +0 -7
  158. package/dist/lib/node-esm/intent-resolver-JFLTVJ7D.mjs.map +0 -7
  159. /package/dist/lib/browser/{AutomationPanel-G3OB6ELR.mjs.map → AutomationPanel-GU37N5LO.mjs.map} +0 -0
  160. /package/dist/lib/browser/{FunctionsPanel-JJPLIAJW.mjs.map → FunctionsPanel-LCCPDIT6.mjs.map} +0 -0
  161. /package/dist/lib/browser/{chunk-QJPKWYTL.mjs.map → chunk-ELQ2FX5G.mjs.map} +0 -0
  162. /package/dist/lib/node/{chunk-L5TWLPGA.cjs.map → chunk-DOLMQUQ5.cjs.map} +0 -0
  163. /package/dist/lib/node-esm/{AutomationPanel-6UXIAJVS.mjs.map → AutomationPanel-HIWEJUWL.mjs.map} +0 -0
  164. /package/dist/lib/node-esm/{FunctionsPanel-J3QGUESH.mjs.map → FunctionsPanel-SBXKWTHR.mjs.map} +0 -0
  165. /package/dist/lib/node-esm/{chunk-TMMB5ETD.mjs.map → chunk-Z7VAQDEE.mjs.map} +0 -0
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Capabilities, contributes, defineModule, definePlugin, Events } from '@dxos/app-framework';
6
- import { FunctionType, FunctionTrigger } from '@dxos/functions/types';
6
+ import { FunctionType, FunctionTrigger } from '@dxos/functions';
7
7
  import { ClientCapabilities, ClientEvents } from '@dxos/plugin-client';
8
8
 
9
9
  import { AppGraphBuilder, IntentResolver, ReactSurface } from './capabilities';
@@ -2,61 +2,85 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, contributes, type PluginsContext } from '@dxos/app-framework';
5
+ import { Rx } from '@effect-rx/rx-react';
6
+ import { Option, pipe } from 'effect';
7
+
8
+ import { Capabilities, contributes, type PluginContext } from '@dxos/app-framework';
6
9
  import { isInstanceOf } from '@dxos/echo-schema';
7
10
  import { ScriptType } from '@dxos/functions';
8
11
  import { PLANK_COMPANION_TYPE, ATTENDABLE_PATH_SEPARATOR } from '@dxos/plugin-deck/types';
9
- import { createExtension, type Node } from '@dxos/plugin-graph';
10
- import { SCRIPT_PLUGIN } from '@dxos/plugin-script/types';
12
+ import { createExtension } from '@dxos/plugin-graph';
11
13
  import { SPACE_PLUGIN } from '@dxos/plugin-space';
12
14
 
13
15
  import { meta } from '../meta';
14
16
 
15
- export default (context: PluginsContext) =>
17
+ export default (context: PluginContext) =>
16
18
  contributes(Capabilities.AppGraphBuilder, [
17
19
  createExtension({
18
20
  id: `${meta.id}/space-settings-automation`,
19
- filter: (node): node is Node<null> => node.type === `${SPACE_PLUGIN}/settings`,
20
- connector: ({ node }) => [
21
- {
22
- id: `automation-${node.id}`,
23
- type: `${meta.id}/space-settings-automation`,
24
- data: `${meta.id}/space-settings-automation`,
25
- properties: {
26
- label: ['automation panel label', { ns: meta.id }],
27
- icon: 'ph--lightning--regular',
28
- },
29
- },
30
- ],
21
+ connector: (node) =>
22
+ Rx.make((get) =>
23
+ pipe(
24
+ get(node),
25
+ Option.flatMap((node) => (node.type === `${SPACE_PLUGIN}/settings` ? Option.some(node) : Option.none())),
26
+ Option.map((node) => [
27
+ {
28
+ id: `automation-${node.id}`,
29
+ type: `${meta.id}/space-settings-automation`,
30
+ data: `${meta.id}/space-settings-automation`,
31
+ properties: {
32
+ label: ['automation panel label', { ns: meta.id }],
33
+ icon: 'ph--lightning--regular',
34
+ },
35
+ },
36
+ ]),
37
+ Option.getOrElse(() => []),
38
+ ),
39
+ ),
31
40
  }),
32
41
  createExtension({
33
42
  id: `${meta.id}/space-settings-functions`,
34
- filter: (node): node is Node<null> => node.type === `${SPACE_PLUGIN}/settings`,
35
- connector: ({ node }) => [
36
- {
37
- id: `functions-${node.id}`,
38
- type: `${meta.id}/space-settings-functions`,
39
- data: `${meta.id}/space-settings-functions`,
40
- properties: {
41
- label: ['functions panel label', { ns: meta.id }],
42
- icon: 'ph--function--regular',
43
- },
44
- },
45
- ],
43
+ connector: (node) =>
44
+ Rx.make((get) =>
45
+ pipe(
46
+ get(node),
47
+ Option.flatMap((node) => (node.type === `${SPACE_PLUGIN}/settings` ? Option.some(node) : Option.none())),
48
+ Option.map((node) => [
49
+ {
50
+ id: `functions-${node.id}`,
51
+ type: `${meta.id}/space-settings-functions`,
52
+ data: `${meta.id}/space-settings-functions`,
53
+ properties: {
54
+ label: ['functions panel label', { ns: meta.id }],
55
+ icon: 'ph--function--regular',
56
+ },
57
+ },
58
+ ]),
59
+ Option.getOrElse(() => []),
60
+ ),
61
+ ),
46
62
  }),
47
63
  createExtension({
48
- id: `${SCRIPT_PLUGIN}/script-companion`,
49
- filter: (node): node is Node<ScriptType> => isInstanceOf(ScriptType, node.data),
50
- connector: ({ node }) => [
51
- {
52
- id: [node.id, 'automation'].join(ATTENDABLE_PATH_SEPARATOR),
53
- type: PLANK_COMPANION_TYPE,
54
- data: 'automation',
55
- properties: {
56
- label: ['script automation label', { ns: meta.id }],
57
- icon: 'ph--lightning--regular',
58
- },
59
- },
60
- ],
64
+ id: `${meta.id}/script-companion`,
65
+ connector: (node) =>
66
+ Rx.make((get) =>
67
+ pipe(
68
+ get(node),
69
+ Option.flatMap((node) => (isInstanceOf(ScriptType, node.data) ? Option.some(node) : Option.none())),
70
+ Option.map((node) => [
71
+ {
72
+ id: [node.id, 'automation'].join(ATTENDABLE_PATH_SEPARATOR),
73
+ type: PLANK_COMPANION_TYPE,
74
+ data: 'automation',
75
+ properties: {
76
+ label: ['script automation label', { ns: meta.id }],
77
+ icon: 'ph--lightning--regular',
78
+ disposition: 'hidden',
79
+ },
80
+ },
81
+ ]),
82
+ Option.getOrElse(() => []),
83
+ ),
84
+ ),
61
85
  }),
62
86
  ]);
@@ -6,10 +6,11 @@ import {
6
6
  contributes,
7
7
  Capabilities,
8
8
  createResolver,
9
- type PluginsContext,
9
+ type PluginContext,
10
10
  createIntent,
11
11
  LayoutAction,
12
12
  } from '@dxos/app-framework';
13
+ import { Ref } from '@dxos/echo';
13
14
  import { FunctionTrigger, FunctionType, ScriptType, TriggerKind } from '@dxos/functions';
14
15
  import { type DXN } from '@dxos/keys';
15
16
  import { live } from '@dxos/live-object';
@@ -19,39 +20,35 @@ import { Filter } from '@dxos/react-client/echo';
19
20
 
20
21
  import { AutomationAction } from '../types';
21
22
 
22
- export default (context: PluginsContext) =>
23
+ export default (context: PluginContext) =>
23
24
  contributes(Capabilities.IntentResolver, [
24
25
  createResolver({
25
26
  intent: AutomationAction.CreateTriggerFromTemplate,
26
- resolve: async ({ space, template, enabled = false, scriptName, payload }) => {
27
- const trigger = live(FunctionTrigger, { enabled });
27
+ resolve: async ({ space, template, enabled = false, scriptName, input }) => {
28
+ const trigger = live(FunctionTrigger, { enabled, input });
28
29
 
29
30
  // TODO(wittjosiah): Factor out function lookup by script name?
30
31
  if (scriptName) {
31
32
  const {
32
33
  objects: [script],
33
- } = await space.db.query(Filter.schema(ScriptType, { name: scriptName })).run();
34
+ } = await space.db.query(Filter.type(ScriptType, { name: scriptName })).run();
34
35
  if (script) {
35
36
  const {
36
37
  objects: [fn],
37
- } = await space.db.query(Filter.schema(FunctionType, { source: script })).run();
38
+ } = await space.db.query(Filter.type(FunctionType, { source: Ref.make(script) })).run();
38
39
  if (fn) {
39
- trigger.function = `dxn:worker:${fn.name}`;
40
+ trigger.function = Ref.make(fn);
40
41
  }
41
42
  }
42
43
  }
43
44
 
44
- if (payload) {
45
- trigger.meta = payload;
46
- }
47
-
48
45
  switch (template.type) {
49
46
  case 'timer': {
50
- trigger.spec = { type: TriggerKind.Timer, cron: template.cron };
47
+ trigger.spec = { kind: TriggerKind.Timer, cron: template.cron };
51
48
  break;
52
49
  }
53
50
  case 'queue': {
54
- trigger.spec = { type: TriggerKind.Queue, queue: (template.queueDXN as DXN).toString() };
51
+ trigger.spec = { kind: TriggerKind.Queue, queue: (template.queueDXN as DXN).toString() };
55
52
  break;
56
53
  }
57
54
  default: {
@@ -6,7 +6,7 @@ import React from 'react';
6
6
 
7
7
  import { Capabilities, contributes, createSurface, useLayout } from '@dxos/app-framework';
8
8
  import { isInstanceOf } from '@dxos/echo-schema';
9
- import { ScriptType } from '@dxos/functions/types';
9
+ import { ScriptType } from '@dxos/functions';
10
10
  import { getSpace, parseId, useSpace } from '@dxos/react-client/echo';
11
11
  import { StackItem } from '@dxos/react-ui-stack';
12
12
 
@@ -7,7 +7,7 @@ import '@dxos-theme';
7
7
  import { type Meta } from '@storybook/react';
8
8
  import React from 'react';
9
9
 
10
- import { FunctionType, FunctionTrigger } from '@dxos/functions/types';
10
+ import { FunctionType, FunctionTrigger } from '@dxos/functions';
11
11
  import { live, useSpaces } from '@dxos/react-client/echo';
12
12
  import { withClientProvider } from '@dxos/react-client/testing';
13
13
  import { withLayout, withTheme } from '@dxos/storybook-utils';
@@ -21,7 +21,7 @@ const DefaultStory = () => {
21
21
  const space = spaces[1];
22
22
 
23
23
  return (
24
- <div role='none' className='w-96'>
24
+ <div className='w-96'>
25
25
  <AutomationPanel space={space} />
26
26
  </div>
27
27
  );
@@ -42,10 +42,11 @@ const meta: Meta = {
42
42
  }
43
43
  },
44
44
  }),
45
- withLayout({ fullscreen: true, tooltips: true, classNames: 'flex juastify-center m-2' }),
45
+ withLayout(),
46
46
  withTheme,
47
47
  ],
48
48
  parameters: {
49
+ layout: 'centered',
49
50
  translations,
50
51
  },
51
52
  };
@@ -2,9 +2,9 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema } from 'effect';
5
6
  import React, { useState } from 'react';
6
7
 
7
- import { S } from '@dxos/echo-schema';
8
8
  import {
9
9
  FunctionType,
10
10
  FunctionTrigger,
@@ -12,7 +12,7 @@ import {
12
12
  TriggerKind,
13
13
  type FunctionTriggerType,
14
14
  ScriptType,
15
- } from '@dxos/functions/types';
15
+ } from '@dxos/functions';
16
16
  import { type Client, useClient } from '@dxos/react-client';
17
17
  import { live, Filter, useQuery, type Space, type Live, getSpace } from '@dxos/react-client/echo';
18
18
  import { Clipboard, IconButton, Input, Separator, useTranslation } from '@dxos/react-ui';
@@ -36,9 +36,9 @@ export type AutomationPanelProps = {
36
36
  export const AutomationPanel = ({ space, object, initialTrigger, onDone }: AutomationPanelProps) => {
37
37
  const { t } = useTranslation(AUTOMATION_PLUGIN);
38
38
  const client = useClient();
39
- const triggers = useQuery(space, Filter.schema(FunctionTrigger));
40
- const functions = useQuery(space, Filter.schema(FunctionType));
41
- const scripts = useQuery(space, Filter.schema(ScriptType));
39
+ const triggers = useQuery(space, Filter.type(FunctionTrigger));
40
+ const functions = useQuery(space, Filter.type(FunctionType));
41
+ const scripts = useQuery(space, Filter.type(ScriptType));
42
42
 
43
43
  const [trigger, setTrigger] = useState<FunctionTriggerType | undefined>(initialTrigger);
44
44
  const [selected, setSelected] = useState<FunctionTrigger>();
@@ -77,15 +77,19 @@ export const AutomationPanel = ({ space, object, initialTrigger, onDone }: Autom
77
77
  onDone?.();
78
78
  };
79
79
 
80
+ if (trigger) {
81
+ return (
82
+ <ControlItem title={t('trigger editor title')}>
83
+ <TriggerEditor space={space} trigger={trigger} onSave={handleSave} onCancel={handleCancel} />
84
+ </ControlItem>
85
+ );
86
+ }
87
+
80
88
  return (
81
89
  <div className='flex flex-col w-full'>
82
- {trigger ? (
83
- <ControlItem title={t('trigger editor title')}>
84
- <TriggerEditor space={space} trigger={trigger} onSave={handleSave} onCancel={handleCancel} />
85
- </ControlItem>
86
- ) : (
87
- <div role='none' className={controlItemClasses}>
88
- <List.Root<FunctionTrigger> items={triggers} isItem={S.is(FunctionTrigger)} getId={(field) => field.id}>
90
+ <div role='none' className={controlItemClasses}>
91
+ {triggers.length > 0 && (
92
+ <List.Root<FunctionTrigger> items={triggers} isItem={Schema.is(FunctionTrigger)} getId={(field) => field.id}>
89
93
  {({ items: triggers }) => (
90
94
  <div role='list' className='flex flex-col w-full'>
91
95
  {triggers?.map((trigger) => {
@@ -127,20 +131,20 @@ export const AutomationPanel = ({ space, object, initialTrigger, onDone }: Autom
127
131
  </div>
128
132
  )}
129
133
  </List.Root>
130
- {triggers.length > 0 && <Separator classNames='mlb-4' />}
131
- <IconButton icon='ph--plus--regular' label={t('new trigger label')} onClick={handleAdd} />
132
- </div>
133
- )}
134
+ )}
135
+ {triggers.length > 0 && <Separator classNames='mlb-4' />}
136
+ <IconButton icon='ph--plus--regular' label={t('new trigger label')} onClick={handleAdd} />
137
+ </div>
134
138
  </div>
135
139
  );
136
140
  };
137
141
 
138
142
  const getCopyAction = (client: Client, trigger: FunctionTrigger | undefined) => {
139
- if (trigger?.spec?.type === TriggerKind.Email) {
143
+ if (trigger?.spec?.kind === TriggerKind.Email) {
140
144
  return { translationKey: 'trigger copy email', contentProvider: () => `${getSpace(trigger)!.id}@dxos.network` };
141
145
  }
142
146
 
143
- if (trigger?.spec?.type === TriggerKind.Webhook) {
147
+ if (trigger?.spec?.kind === TriggerKind.Webhook) {
144
148
  return { translationKey: 'trigger copy url', contentProvider: () => getWebhookUrl(client, trigger) };
145
149
  }
146
150
 
@@ -158,10 +162,11 @@ const getWebhookUrl = (client: Client, trigger: FunctionTrigger) => {
158
162
  const getFunctionName = (scripts: ScriptType[], functions: FunctionType[], trigger: FunctionTriggerType) => {
159
163
  // TODO(wittjosiah): Truncation should be done in the UI.
160
164
  // Warning that the List component is currently a can of worms.
161
- const shortId = trigger.function && `${trigger.function?.slice(0, 16)}…`;
162
- const functionObject = functions.find((fn) => `dxn:worker:${fn.name}` === trigger.function);
165
+ const shortId = trigger.function && `${trigger.function.dxn.toString().slice(0, 16)}…`;
166
+ const functionObject = functions.find((fn) => fn === trigger.function?.target);
163
167
  if (!functionObject) {
164
168
  return shortId;
165
169
  }
170
+
166
171
  return scripts.find((s) => functionObject.source?.target?.id === s.id)?.name ?? shortId;
167
172
  };
@@ -2,11 +2,11 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema } from 'effect';
5
6
  import React, { useCallback, useMemo } from 'react';
6
7
 
7
8
  import { createIntent, LayoutAction, useIntentDispatcher } from '@dxos/app-framework';
8
- import { S } from '@dxos/echo-schema';
9
- import { FunctionType, ScriptType } from '@dxos/functions/types';
9
+ import { FunctionType, ScriptType } from '@dxos/functions';
10
10
  import { Filter, fullyQualifiedId, useQuery, type Space } from '@dxos/react-client/echo';
11
11
  import { Button, useTranslation } from '@dxos/react-ui';
12
12
  import { controlItemClasses } from '@dxos/react-ui-form';
@@ -23,8 +23,8 @@ export type FunctionsPanelProps = {
23
23
 
24
24
  export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
25
25
  const { t } = useTranslation(AUTOMATION_PLUGIN);
26
- const functions = useQuery(space, Filter.schema(FunctionType));
27
- const scripts = useQuery(space, Filter.schema(ScriptType));
26
+ const functions = useQuery(space, Filter.type(FunctionType));
27
+ const scripts = useQuery(space, Filter.type(ScriptType));
28
28
  const { dispatchPromise: dispatch } = useIntentDispatcher();
29
29
 
30
30
  const functionToScriptMap = useMemo(
@@ -65,7 +65,7 @@ export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
65
65
 
66
66
  return (
67
67
  <div role='none' className={mx(controlItemClasses)}>
68
- <List.Root<FunctionType> items={functions} isItem={S.is(FunctionType)} getId={(func) => func.id}>
68
+ <List.Root<FunctionType> items={functions} isItem={Schema.is(FunctionType)} getId={(func) => func.id}>
69
69
  {({ items }) => (
70
70
  <div role='list' className='flex flex-col w-full'>
71
71
  {items?.map((func) => (
@@ -0,0 +1,77 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo } from 'react';
6
+
7
+ import { type JsonPath, RefImpl, toEffectSchema } from '@dxos/echo-schema';
8
+ import { type FunctionType } from '@dxos/functions';
9
+ import { useOnTransition } from '@dxos/react-ui';
10
+ import { Form, type FormInputStateProps, type QueryRefOptions, useFormValues } from '@dxos/react-ui-form';
11
+
12
+ export type FunctionInputEditorProps = {
13
+ functions: FunctionType[];
14
+ onQueryRefOptions: QueryRefOptions;
15
+ } & FormInputStateProps;
16
+
17
+ /**
18
+ * Editor component for function input parameters.
19
+ */
20
+ export const FunctionInputEditor = ({
21
+ functions,
22
+ getValue,
23
+ onValueChange,
24
+ onQueryRefOptions,
25
+ }: FunctionInputEditorProps) => {
26
+ const selectedFunctionValue = useFormValues(['function' as JsonPath]);
27
+ const selectedFunctionId = useMemo(() => {
28
+ if (selectedFunctionValue instanceof RefImpl) {
29
+ return selectedFunctionValue.dxn.toString().split('dxn:echo:@:').at(1);
30
+ }
31
+ }, [selectedFunctionValue]);
32
+
33
+ const selectedFunction = useMemo(
34
+ () => functions.find((f) => f.id === selectedFunctionId),
35
+ [functions, selectedFunctionId],
36
+ );
37
+
38
+ useOnTransition(
39
+ // Clear function parameter input when the function changes.
40
+ selectedFunctionValue,
41
+ (prevValue) => prevValue !== undefined && prevValue !== selectedFunctionValue,
42
+ (currValue) => currValue !== undefined,
43
+ () => onValueChange('object', {}),
44
+ );
45
+
46
+ const inputSchema = useMemo(() => selectedFunction?.inputSchema, [selectedFunction]);
47
+ const effectSchema = useMemo(() => (inputSchema ? toEffectSchema(inputSchema) : undefined), [inputSchema]);
48
+ const propertyCount = inputSchema?.properties ? Object.keys(inputSchema.properties).length : 0;
49
+
50
+ const values = useMemo(() => getValue() ?? {}, [getValue]);
51
+
52
+ const handleValuesChanged = useCallback(
53
+ (values: any) => {
54
+ onValueChange('object', values);
55
+ },
56
+ [onValueChange],
57
+ );
58
+
59
+ if (selectedFunction === undefined || effectSchema === undefined || propertyCount === 0) {
60
+ return null;
61
+ }
62
+
63
+ return (
64
+ <>
65
+ <h3 className='text-md'>Function parameters</h3>
66
+ {/* TODO(ZaymonFC): Try using <FormFields /> internal component for this nesting.
67
+ This would allow errors to flow up to the root context. */}
68
+ <Form
69
+ schema={effectSchema}
70
+ values={values}
71
+ classNames='p-0'
72
+ onValuesChanged={handleValuesChanged}
73
+ onQueryRefOptions={onQueryRefOptions}
74
+ />
75
+ </>
76
+ );
77
+ };
@@ -0,0 +1,59 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo } from 'react';
6
+
7
+ import { type FunctionTriggerType, TriggerKind, type TriggerType } from '@dxos/functions';
8
+ import { useTranslation } from '@dxos/react-ui';
9
+ import { SelectInput, type InputProps, useInputProps } from '@dxos/react-ui-form';
10
+
11
+ import { AUTOMATION_PLUGIN } from '../../meta';
12
+
13
+ export type SpecSelectorProps = InputProps;
14
+
15
+ export const SpecSelector = (props: SpecSelectorProps) => {
16
+ const { t } = useTranslation(AUTOMATION_PLUGIN);
17
+ const specProps = useInputProps(['spec' satisfies keyof FunctionTriggerType]);
18
+
19
+ const handleTypeChange = useCallback(
20
+ (_type: any, value: string): TriggerType | undefined => {
21
+ const getDefaultTriggerSpec = (kind: string) => {
22
+ switch (kind) {
23
+ case TriggerKind.Timer:
24
+ return { kind: TriggerKind.Timer, cron: '' };
25
+ case TriggerKind.Subscription:
26
+ return { kind: TriggerKind.Subscription, filter: {} };
27
+ case TriggerKind.Queue:
28
+ return { kind: TriggerKind.Queue, queue: '' };
29
+ case TriggerKind.Email:
30
+ return { kind: TriggerKind.Email };
31
+ case TriggerKind.Webhook:
32
+ return { kind: TriggerKind.Webhook };
33
+ default:
34
+ return undefined;
35
+ }
36
+ };
37
+
38
+ const defaultSpec = getDefaultTriggerSpec(value);
39
+ if (!defaultSpec) {
40
+ return;
41
+ }
42
+
43
+ // Update the entire spec object, not just the `spec.kind`.
44
+ specProps.onValueChange('object', defaultSpec);
45
+ },
46
+ [specProps],
47
+ );
48
+
49
+ const options = useMemo(
50
+ () =>
51
+ Object.values(TriggerKind).map((kind) => ({
52
+ value: kind,
53
+ label: t(`trigger type ${kind}`),
54
+ })),
55
+ [t],
56
+ );
57
+
58
+ return <SelectInput {...props} options={options} onValueChange={handleTypeChange} />;
59
+ };
@@ -1,5 +1,5 @@
1
1
  //
2
- // Copyright 2024 DXOS.org
2
+ // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
5
  import '@dxos-theme';
@@ -7,10 +7,11 @@ import '@dxos-theme';
7
7
  import { type Meta } from '@storybook/react';
8
8
  import React, { useEffect, useState } from 'react';
9
9
 
10
- import { FunctionType, FunctionTrigger, TriggerKind } from '@dxos/functions/types';
10
+ import { FunctionType, FunctionTrigger, TriggerKind } from '@dxos/functions';
11
11
  import { live } from '@dxos/live-object';
12
+ import { faker } from '@dxos/random';
12
13
  import { useSpaces } from '@dxos/react-client/echo';
13
- import { withClientProvider } from '@dxos/react-client/testing';
14
+ import { ContactType, withClientProvider } from '@dxos/react-client/testing';
14
15
  import { withLayout, withTheme } from '@dxos/storybook-utils';
15
16
 
16
17
  import { TriggerEditor } from './TriggerEditor';
@@ -26,7 +27,7 @@ const DefaultStory = () => {
26
27
  return;
27
28
  }
28
29
 
29
- const trigger = space.db.add(live(FunctionTrigger, { spec: { type: TriggerKind.Timer, cron: '' } }));
30
+ const trigger = space.db.add(live(FunctionTrigger, { spec: { kind: TriggerKind.Timer, cron: '' } }));
30
31
  setTrigger(trigger);
31
32
  }, [space]);
32
33
 
@@ -35,8 +36,8 @@ const DefaultStory = () => {
35
36
  }
36
37
 
37
38
  return (
38
- <div role='none' className='flex w-[350px] border border-separator overflow-hidden'>
39
- <TriggerEditor space={space} trigger={trigger} />
39
+ <div role='none' className='w-[32rem] bs-fit border border-separator rounded-sm'>
40
+ <TriggerEditor space={space} trigger={trigger} onSave={(values) => console.log('on save', values)} />
40
41
  </div>
41
42
  );
42
43
  };
@@ -49,14 +50,22 @@ const meta: Meta = {
49
50
  withClientProvider({
50
51
  createIdentity: true,
51
52
  createSpace: true,
52
- types: [FunctionType, FunctionTrigger],
53
+ types: [FunctionType, FunctionTrigger, ContactType],
53
54
  onSpaceCreated: ({ space }) => {
54
55
  for (const fn of functions) {
55
56
  space.db.add(live(FunctionType, fn));
56
57
  }
58
+ Array.from({ length: 10 }).map(() => {
59
+ return space.db.add(
60
+ live(ContactType, {
61
+ name: faker.person.fullName(),
62
+ identifiers: [],
63
+ }),
64
+ );
65
+ });
57
66
  },
58
67
  }),
59
- withLayout({ fullscreen: true, tooltips: true, classNames: 'flex justify-center m-2' }),
68
+ withLayout({ fullscreen: true, classNames: 'flex justify-center m-2' }),
60
69
  withTheme,
61
70
  ],
62
71
  parameters: {