@dxos/plugin-automation 0.8.4-main.5ad4a44 → 0.8.4-main.66e292d
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/dist/lib/browser/AutomationPanel-M4M77L4V.mjs +11 -0
- package/dist/lib/browser/{AutomationSettings-3LABN6ER.mjs → AutomationSettings-4HCI6KJR.mjs} +6 -7
- package/dist/lib/{node-esm/AutomationSettings-XENNIIZM.mjs.map → browser/AutomationSettings-4HCI6KJR.mjs.map} +1 -1
- package/dist/lib/browser/FunctionsContainer-CDVBRQCT.mjs +144 -0
- package/dist/lib/browser/FunctionsContainer-CDVBRQCT.mjs.map +7 -0
- package/dist/lib/browser/{FunctionsPanel-NRIKAPQV.mjs → FunctionsPanel-CRW6SJUN.mjs} +3 -3
- package/dist/lib/browser/{app-graph-builder-DV5HMFX4.mjs → app-graph-builder-W7LLC6XW.mjs} +7 -7
- package/dist/lib/browser/app-graph-builder-W7LLC6XW.mjs.map +7 -0
- package/dist/lib/browser/chunk-4MBM6C6A.mjs +100 -0
- package/dist/lib/browser/chunk-4MBM6C6A.mjs.map +7 -0
- package/dist/lib/browser/{chunk-NIJWEQRD.mjs → chunk-7W6QMY3L.mjs} +26 -42
- package/dist/lib/browser/chunk-7W6QMY3L.mjs.map +7 -0
- package/dist/lib/browser/{chunk-AY67OUDA.mjs → chunk-CZVA5NMD.mjs} +5 -5
- package/dist/lib/browser/chunk-LZQFZO3B.mjs +17 -0
- package/dist/lib/browser/chunk-LZQFZO3B.mjs.map +7 -0
- package/dist/lib/browser/{chunk-LC3QQU47.mjs → chunk-T6ZESHDY.mjs} +38 -18
- package/dist/lib/browser/chunk-T6ZESHDY.mjs.map +7 -0
- package/dist/lib/browser/{chunk-DLLE4FKP.mjs → chunk-TWWFNOIR.mjs} +27 -12
- package/dist/lib/browser/chunk-TWWFNOIR.mjs.map +7 -0
- package/dist/lib/browser/{chunk-5ARH77PV.mjs → chunk-XAKZ4ANY.mjs} +2 -2
- package/dist/lib/browser/chunk-XAKZ4ANY.mjs.map +7 -0
- package/dist/lib/browser/{chunk-VGBZKM3O.mjs → chunk-YBPJCY3F.mjs} +2 -2
- package/dist/lib/browser/compute-runtime-B4XJVY4Y.mjs +113 -0
- package/dist/lib/browser/compute-runtime-B4XJVY4Y.mjs.map +7 -0
- package/dist/lib/browser/hooks/index.mjs +5 -4
- package/dist/lib/browser/index.mjs +19 -10
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-D2OHKQRR.mjs → intent-resolver-5HR7M7T6.mjs} +8 -8
- package/dist/lib/browser/intent-resolver-5HR7M7T6.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-JXFO46V4.mjs → react-surface-TKU2EQ5A.mjs} +6 -5
- package/dist/lib/browser/react-surface-TKU2EQ5A.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +2 -2
- package/dist/lib/node-esm/{AutomationPanel-GHK5UG4K.mjs → AutomationPanel-F5CTC6AT.mjs} +4 -4
- package/dist/lib/node-esm/{AutomationSettings-XENNIIZM.mjs → AutomationSettings-BQLJIFRT.mjs} +6 -7
- package/dist/lib/node-esm/FunctionsContainer-ZHHJPQAZ.mjs +145 -0
- package/dist/lib/node-esm/FunctionsContainer-ZHHJPQAZ.mjs.map +7 -0
- package/dist/lib/node-esm/{FunctionsPanel-SAMRTELO.mjs → FunctionsPanel-RVVCS6VH.mjs} +3 -3
- package/dist/lib/node-esm/{app-graph-builder-TR2WXPX2.mjs → app-graph-builder-SLQOO7GH.mjs} +7 -7
- package/dist/lib/node-esm/app-graph-builder-SLQOO7GH.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-LWASMQIF.mjs → chunk-3IYSC75Z.mjs} +5 -5
- package/dist/lib/node-esm/chunk-7B6NAAI6.mjs +101 -0
- package/dist/lib/node-esm/chunk-7B6NAAI6.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-5MQJPJR2.mjs → chunk-CEVIVRTY.mjs} +6 -2
- package/dist/lib/node-esm/chunk-CEVIVRTY.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-EX74SIDO.mjs → chunk-CF2SWXPW.mjs} +26 -42
- package/dist/lib/node-esm/chunk-CF2SWXPW.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-CJUI6AKX.mjs → chunk-ECJKIUBO.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-3EWMZAU6.mjs → chunk-F76XVENA.mjs} +38 -18
- package/dist/lib/node-esm/chunk-F76XVENA.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-WHCSOUNN.mjs → chunk-KB7NFEYY.mjs} +2 -2
- package/dist/lib/node-esm/chunk-KB7NFEYY.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-YQXW3JXD.mjs → chunk-RVK52XGK.mjs} +27 -12
- package/dist/lib/node-esm/chunk-RVK52XGK.mjs.map +7 -0
- package/dist/lib/node-esm/compute-runtime-JUWTQXOV.mjs +114 -0
- package/dist/lib/node-esm/compute-runtime-JUWTQXOV.mjs.map +7 -0
- package/dist/lib/node-esm/hooks/index.mjs +5 -4
- package/dist/lib/node-esm/index.mjs +19 -10
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-2LGBVXT5.mjs → intent-resolver-KDRYB5BC.mjs} +8 -8
- package/dist/lib/node-esm/intent-resolver-KDRYB5BC.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{react-surface-YDJ43B3N.mjs → react-surface-7QROSEGH.mjs} +6 -5
- package/dist/lib/node-esm/react-surface-7QROSEGH.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +2 -2
- package/dist/types/src/capabilities/capabilities.d.ts +2 -1
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/compute-runtime.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +2 -2
- package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +1 -1
- package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts +3 -0
- package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts.map +1 -1
- package/dist/types/src/components/FunctionsContainer.d.ts.map +1 -1
- package/dist/types/src/components/FunctionsPanel/FunctionsPanel.d.ts.map +1 -1
- package/dist/types/src/components/FunctionsRegistry/FunctionsRegistry.d.ts +8 -0
- package/dist/types/src/components/FunctionsRegistry/FunctionsRegistry.d.ts.map +1 -0
- package/dist/types/src/components/FunctionsRegistry/index.d.ts +2 -0
- package/dist/types/src/components/FunctionsRegistry/index.d.ts.map +1 -0
- package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts +2 -2
- package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts.map +1 -1
- package/dist/types/src/components/TriggerEditor/SpecSelector.d.ts.map +1 -1
- package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +6 -5
- package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
- package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts +3 -1
- package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useComputeRuntimeCallback.d.ts +5 -1
- package/dist/types/src/hooks/useComputeRuntimeCallback.d.ts.map +1 -1
- package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts +2 -2
- package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/test-functions.d.ts +2 -3
- package/dist/types/src/testing/test-functions.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +36 -33
- package/src/AutomationPlugin.tsx +2 -2
- package/src/capabilities/app-graph-builder.ts +6 -6
- package/src/capabilities/capabilities.ts +2 -9
- package/src/capabilities/compute-runtime.ts +27 -36
- package/src/capabilities/intent-resolver.ts +5 -5
- package/src/capabilities/react-surface.tsx +2 -1
- package/src/components/AutomationPanel/AutomationPanel.stories.tsx +4 -5
- package/src/components/AutomationPanel/AutomationPanel.tsx +48 -35
- package/src/components/FunctionsContainer.tsx +7 -0
- package/src/components/FunctionsPanel/FunctionsPanel.tsx +32 -13
- package/src/components/FunctionsRegistry/FunctionsRegistry.tsx +127 -0
- package/src/components/FunctionsRegistry/index.ts +5 -0
- package/src/components/TriggerEditor/FunctionInputEditor.tsx +2 -2
- package/src/components/TriggerEditor/SpecSelector.tsx +4 -5
- package/src/components/TriggerEditor/TriggerEditor.stories.tsx +37 -16
- package/src/components/TriggerEditor/TriggerEditor.tsx +24 -54
- package/src/hooks/useComputeRuntimeCallback.ts +40 -2
- package/src/hooks/useTriggerRuntimeControls.ts +4 -3
- package/src/index.ts +1 -0
- package/src/meta.ts +5 -2
- package/src/testing/test-functions.ts +2 -2
- package/src/translations.ts +3 -0
- package/dist/lib/browser/AutomationPanel-PNBH5L5C.mjs +0 -11
- package/dist/lib/browser/FunctionsContainer-HHBMPUOD.mjs +0 -36
- package/dist/lib/browser/FunctionsContainer-HHBMPUOD.mjs.map +0 -7
- package/dist/lib/browser/app-graph-builder-DV5HMFX4.mjs.map +0 -7
- package/dist/lib/browser/chunk-5ARH77PV.mjs.map +0 -7
- package/dist/lib/browser/chunk-DLLE4FKP.mjs.map +0 -7
- package/dist/lib/browser/chunk-LC3QQU47.mjs.map +0 -7
- package/dist/lib/browser/chunk-MVPRI3DB.mjs +0 -53
- package/dist/lib/browser/chunk-MVPRI3DB.mjs.map +0 -7
- package/dist/lib/browser/chunk-NIJWEQRD.mjs.map +0 -7
- package/dist/lib/browser/chunk-QT3YWUOT.mjs +0 -14
- package/dist/lib/browser/chunk-QT3YWUOT.mjs.map +0 -7
- package/dist/lib/browser/chunk-WWURMV25.mjs +0 -13
- package/dist/lib/browser/chunk-WWURMV25.mjs.map +0 -7
- package/dist/lib/browser/compute-runtime-YJREH6WP.mjs +0 -160
- package/dist/lib/browser/compute-runtime-YJREH6WP.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-D2OHKQRR.mjs.map +0 -7
- package/dist/lib/browser/react-surface-JXFO46V4.mjs.map +0 -7
- package/dist/lib/node-esm/FunctionsContainer-ZKVOBUHV.mjs +0 -37
- package/dist/lib/node-esm/FunctionsContainer-ZKVOBUHV.mjs.map +0 -7
- package/dist/lib/node-esm/app-graph-builder-TR2WXPX2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-3EWMZAU6.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-5MQJPJR2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-EX74SIDO.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-QCA543ZR.mjs +0 -54
- package/dist/lib/node-esm/chunk-QCA543ZR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-U7LJXQS4.mjs +0 -16
- package/dist/lib/node-esm/chunk-U7LJXQS4.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-WHCSOUNN.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YQXW3JXD.mjs.map +0 -7
- package/dist/lib/node-esm/compute-runtime-CMEPAYND.mjs +0 -161
- package/dist/lib/node-esm/compute-runtime-CMEPAYND.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-2LGBVXT5.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-YDJ43B3N.mjs.map +0 -7
- /package/dist/lib/browser/{AutomationPanel-PNBH5L5C.mjs.map → AutomationPanel-M4M77L4V.mjs.map} +0 -0
- /package/dist/lib/browser/{FunctionsPanel-NRIKAPQV.mjs.map → FunctionsPanel-CRW6SJUN.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-AY67OUDA.mjs.map → chunk-CZVA5NMD.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-VGBZKM3O.mjs.map → chunk-YBPJCY3F.mjs.map} +0 -0
- /package/dist/lib/node-esm/{AutomationPanel-GHK5UG4K.mjs.map → AutomationPanel-F5CTC6AT.mjs.map} +0 -0
- /package/dist/lib/{browser/AutomationSettings-3LABN6ER.mjs.map → node-esm/AutomationSettings-BQLJIFRT.mjs.map} +0 -0
- /package/dist/lib/node-esm/{FunctionsPanel-SAMRTELO.mjs.map → FunctionsPanel-RVVCS6VH.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-LWASMQIF.mjs.map → chunk-3IYSC75Z.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-CJUI6AKX.mjs.map → chunk-ECJKIUBO.mjs.map} +0 -0
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
import React, { useCallback, useMemo } from 'react';
|
|
7
7
|
|
|
8
|
-
import { LayoutAction, createIntent
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
8
|
+
import { LayoutAction, createIntent } from '@dxos/app-framework';
|
|
9
|
+
import { useIntentDispatcher } from '@dxos/app-framework/react';
|
|
10
|
+
import { Obj } from '@dxos/echo';
|
|
11
|
+
import { Function, Script } from '@dxos/functions';
|
|
12
|
+
import { SpaceAction } from '@dxos/plugin-space/types';
|
|
13
|
+
import { Filter, type Space, useQuery } from '@dxos/react-client/echo';
|
|
14
|
+
import { Button, IconButton, useTranslation } from '@dxos/react-ui';
|
|
12
15
|
import { controlItemClasses } from '@dxos/react-ui-form';
|
|
13
16
|
import { List } from '@dxos/react-ui-list';
|
|
14
17
|
import { ghostHover, mx } from '@dxos/react-ui-theme';
|
|
@@ -23,8 +26,8 @@ export type FunctionsPanelProps = {
|
|
|
23
26
|
|
|
24
27
|
export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
|
|
25
28
|
const { t } = useTranslation(meta.id);
|
|
26
|
-
const functions = useQuery(space, Filter.type(
|
|
27
|
-
const scripts = useQuery(space, Filter.type(
|
|
29
|
+
const functions = useQuery(space, Filter.type(Function.Function));
|
|
30
|
+
const scripts = useQuery(space, Filter.type(Script.Script));
|
|
28
31
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
29
32
|
|
|
30
33
|
const functionToScriptMap = useMemo(
|
|
@@ -40,13 +43,13 @@ export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
|
|
|
40
43
|
}
|
|
41
44
|
return map;
|
|
42
45
|
},
|
|
43
|
-
{} as Record<string,
|
|
46
|
+
{} as Record<string, Script.Script>,
|
|
44
47
|
),
|
|
45
48
|
[functions, scripts],
|
|
46
49
|
);
|
|
47
50
|
|
|
48
51
|
const getScriptName = useCallback(
|
|
49
|
-
(func:
|
|
52
|
+
(func: Function.Function) => {
|
|
50
53
|
const script = functionToScriptMap[func.id];
|
|
51
54
|
return script?.name;
|
|
52
55
|
},
|
|
@@ -54,23 +57,33 @@ export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
|
|
|
54
57
|
);
|
|
55
58
|
|
|
56
59
|
const handleGoToScript = useCallback(
|
|
57
|
-
(func:
|
|
60
|
+
(func: Function.Function) => {
|
|
58
61
|
const script = functionToScriptMap[func.id];
|
|
59
62
|
if (script) {
|
|
60
|
-
void dispatch(
|
|
63
|
+
void dispatch(
|
|
64
|
+
createIntent(LayoutAction.Open, {
|
|
65
|
+
part: 'main',
|
|
66
|
+
subject: [Obj.getDXN(script).toString()],
|
|
67
|
+
}),
|
|
68
|
+
);
|
|
61
69
|
}
|
|
62
70
|
},
|
|
63
71
|
[functionToScriptMap, dispatch],
|
|
64
72
|
);
|
|
65
73
|
|
|
74
|
+
const handleDelete = useCallback(
|
|
75
|
+
(func: Function.Function) => dispatch(createIntent(SpaceAction.RemoveObjects, { objects: [func] })),
|
|
76
|
+
[dispatch],
|
|
77
|
+
);
|
|
78
|
+
|
|
66
79
|
return (
|
|
67
80
|
<div role='none' className={mx(controlItemClasses)}>
|
|
68
81
|
{functions.length > 0 && (
|
|
69
|
-
<List.Root<
|
|
82
|
+
<List.Root<Function.Function> items={functions} isItem={Schema.is(Function.Function)} getId={(func) => func.id}>
|
|
70
83
|
{({ items }) => (
|
|
71
|
-
<div role='list' className='flex flex-col
|
|
84
|
+
<div role='list' className='flex flex-col is-full'>
|
|
72
85
|
{items?.map((func) => (
|
|
73
|
-
<List.Item<
|
|
86
|
+
<List.Item<Function.Function>
|
|
74
87
|
key={func.id}
|
|
75
88
|
item={func}
|
|
76
89
|
classNames={mx(grid, ghostHover, 'items-center', 'pli-2', 'min-bs-[3rem]')}
|
|
@@ -84,6 +97,12 @@ export const FunctionsPanel = ({ space }: FunctionsPanelProps) => {
|
|
|
84
97
|
{functionToScriptMap[func.id] && (
|
|
85
98
|
<Button onClick={() => handleGoToScript(func)}>{t('go to function source button label')}</Button>
|
|
86
99
|
)}
|
|
100
|
+
<IconButton
|
|
101
|
+
iconOnly
|
|
102
|
+
icon='ph--trash--regular'
|
|
103
|
+
label={t('delete function button label')}
|
|
104
|
+
onClick={() => handleDelete(func)}
|
|
105
|
+
/>
|
|
87
106
|
</List.Item>
|
|
88
107
|
))}
|
|
89
108
|
</div>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Array from 'effect/Array';
|
|
6
|
+
import * as EffectFunction from 'effect/Function';
|
|
7
|
+
import * as Order from 'effect/Order';
|
|
8
|
+
import * as Schema from 'effect/Schema';
|
|
9
|
+
import { useState } from 'react';
|
|
10
|
+
import React, { useCallback } from 'react';
|
|
11
|
+
|
|
12
|
+
import { Function } from '@dxos/functions';
|
|
13
|
+
import { getDeployedFunctions } from '@dxos/functions-runtime/edge';
|
|
14
|
+
import { useClient } from '@dxos/react-client';
|
|
15
|
+
import { Filter, Query, type Space, useQuery } from '@dxos/react-client/echo';
|
|
16
|
+
import { useAsyncEffect } from '@dxos/react-ui';
|
|
17
|
+
import { IconButton, useTranslation } from '@dxos/react-ui';
|
|
18
|
+
import { controlItemClasses } from '@dxos/react-ui-form';
|
|
19
|
+
import { List } from '@dxos/react-ui-list';
|
|
20
|
+
import { ghostHover, mx } from '@dxos/react-ui-theme';
|
|
21
|
+
|
|
22
|
+
import { meta } from '../../meta';
|
|
23
|
+
|
|
24
|
+
const grid = 'grid grid-cols-[1fr_1fr_auto] min-bs-[2.5rem]';
|
|
25
|
+
|
|
26
|
+
type FunctionsRegistryProps = {
|
|
27
|
+
space: Space;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const FunctionsRegistry = ({ space }: FunctionsRegistryProps) => {
|
|
31
|
+
const client = useClient();
|
|
32
|
+
const [loading, setLoading] = useState(true);
|
|
33
|
+
const [functions, setFunctions] = useState<Function.Function[]>([]);
|
|
34
|
+
const { t } = useTranslation(meta.id);
|
|
35
|
+
|
|
36
|
+
const dbFunctions = useQuery(space, Filter.type(Function.Function));
|
|
37
|
+
|
|
38
|
+
const state = (func: Function.Function) => {
|
|
39
|
+
const dbFunction = dbFunctions.find((f) => f.key === func.key);
|
|
40
|
+
if (!dbFunction) {
|
|
41
|
+
return 'import';
|
|
42
|
+
}
|
|
43
|
+
if (dbFunction.version === func.version && dbFunction.updated === func.updated) {
|
|
44
|
+
return 'none';
|
|
45
|
+
}
|
|
46
|
+
return 'update';
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
useAsyncEffect(async () => {
|
|
50
|
+
setLoading(true);
|
|
51
|
+
const functions = await getDeployedFunctions(client);
|
|
52
|
+
setFunctions(functions);
|
|
53
|
+
setLoading(false);
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
const dedupedFunctions = EffectFunction.pipe(
|
|
57
|
+
functions,
|
|
58
|
+
Array.filter((_) => _.key !== undefined),
|
|
59
|
+
Array.sort(Order.reverse(Order.mapInput(Order.string, (_: Function.Function) => _.updated ?? ''))),
|
|
60
|
+
Array.dedupeWith((self, that) => self.key === that.key),
|
|
61
|
+
Array.sort(Order.mapInput(Order.string, (_: Function.Function) => _.key ?? '')),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const hanleImportOrUpdate = useCallback(
|
|
65
|
+
async (func: Function.Function) => {
|
|
66
|
+
const {
|
|
67
|
+
objects: [existingFunc],
|
|
68
|
+
} = await space.db.query(Query.type(Function.Function, { key: func.key })).run();
|
|
69
|
+
if (!existingFunc) {
|
|
70
|
+
space.db.add(func);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
Function.setFrom(existingFunc, func);
|
|
74
|
+
},
|
|
75
|
+
[space],
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div role='none' className={mx(controlItemClasses)}>
|
|
80
|
+
{dedupedFunctions.length > 0 && (
|
|
81
|
+
<List.Root<Function.Function>
|
|
82
|
+
items={dedupedFunctions}
|
|
83
|
+
isItem={Schema.is(Function.Function)}
|
|
84
|
+
getId={(func) => func.id}
|
|
85
|
+
>
|
|
86
|
+
{({ items }) => (
|
|
87
|
+
<div role='list' className='flex flex-col is-full'>
|
|
88
|
+
{items?.map((func) => (
|
|
89
|
+
<List.Item<Function.Function>
|
|
90
|
+
key={func.id}
|
|
91
|
+
item={func}
|
|
92
|
+
classNames={mx(grid, ghostHover, 'items-center', 'pli-2', 'min-bs-[3rem]')}
|
|
93
|
+
>
|
|
94
|
+
<div className='flex flex-col truncate'>
|
|
95
|
+
<List.ItemTitle classNames='truncate'>{func.name}</List.ItemTitle>
|
|
96
|
+
<div className='text-xs text-description truncate'>{func.key}</div>
|
|
97
|
+
</div>
|
|
98
|
+
<div className='flex flex-col truncate'>
|
|
99
|
+
<div className='text-xs text-description truncate'>{func.version}</div>
|
|
100
|
+
<div className='text-xs text-description truncate'>
|
|
101
|
+
{func.updated ? `Uploaded ${new Date(func.updated).toLocaleString()}` : ''}
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<IconButton
|
|
106
|
+
iconOnly
|
|
107
|
+
icon={state(func) === 'update' ? 'ph--arrows-clockwise--regular' : 'ph--download--regular'}
|
|
108
|
+
label={
|
|
109
|
+
state(func) === 'update' ? t('update function button label') : t('import function button label')
|
|
110
|
+
}
|
|
111
|
+
disabled={state(func) === 'none'}
|
|
112
|
+
onClick={() => hanleImportOrUpdate(func)}
|
|
113
|
+
/>
|
|
114
|
+
</List.Item>
|
|
115
|
+
))}
|
|
116
|
+
</div>
|
|
117
|
+
)}
|
|
118
|
+
</List.Root>
|
|
119
|
+
)}
|
|
120
|
+
|
|
121
|
+
{dedupedFunctions.length === 0 && !loading && (
|
|
122
|
+
<div className='text-center plb-4 text-gray-500'>{t('no functions found')}</div>
|
|
123
|
+
)}
|
|
124
|
+
{loading && <div className='text-center plb-4 text-gray-500'>{t('loading functions')}</div>}
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
@@ -6,12 +6,12 @@ import React, { useCallback, useMemo } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { Ref, Type } from '@dxos/echo';
|
|
8
8
|
import { type JsonPath } from '@dxos/echo/internal';
|
|
9
|
-
import { type
|
|
9
|
+
import { type Function } from '@dxos/functions';
|
|
10
10
|
import { useOnTransition } from '@dxos/react-ui';
|
|
11
11
|
import { Form, type FormInputStateProps, type QueryRefOptions, useFormValues } from '@dxos/react-ui-form';
|
|
12
12
|
|
|
13
13
|
export type FunctionInputEditorProps = {
|
|
14
|
-
functions:
|
|
14
|
+
functions: Function.Function[];
|
|
15
15
|
onQueryRefOptions: QueryRefOptions;
|
|
16
16
|
} & FormInputStateProps;
|
|
17
17
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import React, { useCallback, useMemo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { Filter, Query } from '@dxos/echo';
|
|
8
|
-
import {
|
|
8
|
+
import { Trigger } from '@dxos/functions';
|
|
9
9
|
import { useTranslation } from '@dxos/react-ui';
|
|
10
10
|
import { type InputProps, SelectInput, useInputProps } from '@dxos/react-ui-form';
|
|
11
11
|
|
|
@@ -15,10 +15,10 @@ export type SpecSelectorProps = InputProps;
|
|
|
15
15
|
|
|
16
16
|
export const SpecSelector = (props: SpecSelectorProps) => {
|
|
17
17
|
const { t } = useTranslation(meta.id);
|
|
18
|
-
const specProps = useInputProps(['spec' satisfies keyof
|
|
18
|
+
const specProps = useInputProps(['spec' satisfies keyof Trigger.Trigger]);
|
|
19
19
|
|
|
20
20
|
const handleTypeChange = useCallback(
|
|
21
|
-
(_type: any, value: string):
|
|
21
|
+
(_type: any, value: string): Trigger.Spec | undefined => {
|
|
22
22
|
const getDefaultTriggerSpec = (kind: string) => {
|
|
23
23
|
switch (kind) {
|
|
24
24
|
case 'timer':
|
|
@@ -27,7 +27,6 @@ export const SpecSelector = (props: SpecSelectorProps) => {
|
|
|
27
27
|
return {
|
|
28
28
|
kind: 'subscription',
|
|
29
29
|
query: {
|
|
30
|
-
string: 'Query.select(Filter.nothing())',
|
|
31
30
|
ast: Query.select(Filter.nothing()).ast,
|
|
32
31
|
},
|
|
33
32
|
};
|
|
@@ -55,7 +54,7 @@ export const SpecSelector = (props: SpecSelectorProps) => {
|
|
|
55
54
|
|
|
56
55
|
const options = useMemo(
|
|
57
56
|
() =>
|
|
58
|
-
|
|
57
|
+
Trigger.Kinds.map((kind) => ({
|
|
59
58
|
value: kind,
|
|
60
59
|
label: t(`trigger type ${kind}`),
|
|
61
60
|
})),
|
|
@@ -5,35 +5,45 @@
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
import React, { useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import { Filter, Obj, Ref } from '@dxos/echo';
|
|
9
|
-
import {
|
|
8
|
+
import { Filter, Obj, Ref, Tag, Type } from '@dxos/echo';
|
|
9
|
+
import { Function } from '@dxos/functions';
|
|
10
|
+
import { Trigger } from '@dxos/functions';
|
|
10
11
|
import { invariant } from '@dxos/invariant';
|
|
11
12
|
import { faker } from '@dxos/random';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
13
|
+
import { useQuery } from '@dxos/react-client/echo';
|
|
14
|
+
import { TestSchema, useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
14
15
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
15
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
16
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
17
|
+
import { Employer, Organization, Person, Project } from '@dxos/types';
|
|
16
18
|
|
|
17
19
|
import { functions } from '../../testing';
|
|
18
20
|
import { translations } from '../../translations';
|
|
19
21
|
|
|
20
22
|
import { TriggerEditor, type TriggerEditorProps } from './TriggerEditor';
|
|
21
23
|
|
|
24
|
+
const types = [
|
|
25
|
+
// TODO(burdon): Get label from annotation.
|
|
26
|
+
{ value: Organization.Organization.typename, label: 'Organization' },
|
|
27
|
+
{ value: Person.Person.typename, label: 'Person' },
|
|
28
|
+
{ value: Type.getTypename(Project.Project), label: 'Project' },
|
|
29
|
+
{ value: Employer.Employer.typename, label: 'Employer' },
|
|
30
|
+
];
|
|
31
|
+
|
|
22
32
|
const DefaultStory = (props: Partial<TriggerEditorProps>) => {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
33
|
+
const { space } = useClientProvider();
|
|
34
|
+
const [trigger, setTrigger] = useState<Trigger.Trigger>();
|
|
35
|
+
const tags = useQuery(space, Filter.type(Tag.Tag));
|
|
26
36
|
|
|
27
37
|
useAsyncEffect(async () => {
|
|
28
38
|
if (!space) {
|
|
29
39
|
return;
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
const result = await space.db.query(Filter.type(
|
|
42
|
+
const result = await space.db.query(Filter.type(Function.Function)).run();
|
|
33
43
|
const fn = result.objects.find((fn) => fn.name === 'example.com/function/forex');
|
|
34
44
|
invariant(fn);
|
|
35
45
|
const trigger = space.db.add(
|
|
36
|
-
|
|
46
|
+
Trigger.make({
|
|
37
47
|
function: Ref.make(fn),
|
|
38
48
|
spec: { kind: 'webhook' },
|
|
39
49
|
input: {
|
|
@@ -50,8 +60,15 @@ const DefaultStory = (props: Partial<TriggerEditorProps>) => {
|
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
return (
|
|
53
|
-
<div role='none' className='
|
|
54
|
-
<TriggerEditor
|
|
63
|
+
<div role='none' className='is-[32rem] bs-fit border border-separator rounded-sm'>
|
|
64
|
+
<TriggerEditor
|
|
65
|
+
space={space}
|
|
66
|
+
trigger={trigger}
|
|
67
|
+
types={types}
|
|
68
|
+
tags={tags}
|
|
69
|
+
onSave={(values) => console.log('on save', values)}
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
55
72
|
</div>
|
|
56
73
|
);
|
|
57
74
|
};
|
|
@@ -62,17 +79,22 @@ const meta = {
|
|
|
62
79
|
render: DefaultStory,
|
|
63
80
|
decorators: [
|
|
64
81
|
withTheme,
|
|
82
|
+
withLayout({ container: 'column' }),
|
|
65
83
|
withClientProvider({
|
|
66
84
|
createIdentity: true,
|
|
67
85
|
createSpace: true,
|
|
68
|
-
types: [
|
|
86
|
+
types: [Tag.Tag, Function.Function, Trigger.Trigger, TestSchema.ContactType],
|
|
69
87
|
onCreateSpace: ({ space }) => {
|
|
88
|
+
space.db.add(Tag.make({ label: 'Important' }));
|
|
89
|
+
space.db.add(Tag.make({ label: 'Investor' }));
|
|
90
|
+
space.db.add(Tag.make({ label: 'New' }));
|
|
91
|
+
|
|
70
92
|
for (const fn of functions) {
|
|
71
|
-
space.db.add(
|
|
93
|
+
space.db.add(Function.make(fn));
|
|
72
94
|
}
|
|
73
95
|
Array.from({ length: 10 }).map(() => {
|
|
74
96
|
return space.db.add(
|
|
75
|
-
Obj.make(ContactType, {
|
|
97
|
+
Obj.make(TestSchema.ContactType, {
|
|
76
98
|
name: faker.person.fullName(),
|
|
77
99
|
identifiers: [],
|
|
78
100
|
}),
|
|
@@ -82,7 +104,6 @@ const meta = {
|
|
|
82
104
|
}),
|
|
83
105
|
],
|
|
84
106
|
parameters: {
|
|
85
|
-
layout: 'column',
|
|
86
107
|
translations,
|
|
87
108
|
},
|
|
88
109
|
} satisfies Meta<typeof DefaultStory>;
|
|
@@ -5,41 +5,38 @@
|
|
|
5
5
|
import React, { useCallback, useMemo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { ComputeGraph } from '@dxos/conductor';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { DXN, type Query } from '@dxos/echo';
|
|
9
|
+
import { Function, Script, Trigger } from '@dxos/functions';
|
|
10
10
|
import { Filter, Ref, type Space, useQuery } from '@dxos/react-client/echo';
|
|
11
|
-
import { Input
|
|
12
|
-
import {
|
|
11
|
+
import { Input } from '@dxos/react-ui';
|
|
12
|
+
import { QueryForm, type QueryFormProps } from '@dxos/react-ui-components';
|
|
13
13
|
import { type CustomInputMap, Form, InputHeader, SelectInput, useRefQueryLookupHandler } from '@dxos/react-ui-form';
|
|
14
|
-
import { inputTheme, mx } from '@dxos/react-ui-theme';
|
|
15
|
-
|
|
16
|
-
import { meta } from '../../meta';
|
|
17
14
|
|
|
18
15
|
import { FunctionInputEditor, type FunctionInputEditorProps } from './FunctionInputEditor';
|
|
19
16
|
import { SpecSelector } from './SpecSelector';
|
|
20
17
|
|
|
21
18
|
export type TriggerEditorProps = {
|
|
22
19
|
space: Space;
|
|
23
|
-
trigger:
|
|
20
|
+
trigger: Trigger.Trigger;
|
|
24
21
|
// TODO(wittjosiah): This needs to apply to whole spec but currently only applies to spec.kind & spec.query.
|
|
25
22
|
readonlySpec?: boolean;
|
|
26
|
-
onSave?: (trigger: Omit<
|
|
23
|
+
onSave?: (trigger: Omit<Trigger.Trigger, 'id'>) => void;
|
|
27
24
|
onCancel?: () => void;
|
|
28
|
-
}
|
|
25
|
+
} & Pick<QueryFormProps, 'types' | 'tags'>;
|
|
29
26
|
|
|
30
|
-
export const TriggerEditor = ({ space, trigger, readonlySpec, onSave, onCancel }: TriggerEditorProps) => {
|
|
31
|
-
const handleSave = (values:
|
|
27
|
+
export const TriggerEditor = ({ space, trigger, readonlySpec, types, tags, onSave, onCancel }: TriggerEditorProps) => {
|
|
28
|
+
const handleSave = ({ id: _, ...values }: Trigger.Trigger) => {
|
|
32
29
|
onSave?.(values);
|
|
33
30
|
};
|
|
34
31
|
|
|
35
32
|
const handleRefQueryLookup = useRefQueryLookupHandler({ space });
|
|
36
|
-
const Custom = useCustomInputs({ space, readonlySpec, onQueryRefOptions: handleRefQueryLookup });
|
|
33
|
+
const Custom = useCustomInputs({ space, readonlySpec, types, tags, onQueryRefOptions: handleRefQueryLookup });
|
|
37
34
|
|
|
38
35
|
return (
|
|
39
36
|
<Form
|
|
40
37
|
outerSpacing={false}
|
|
41
38
|
Custom={Custom}
|
|
42
|
-
schema={
|
|
39
|
+
schema={Trigger.Trigger}
|
|
43
40
|
values={trigger}
|
|
44
41
|
onSave={handleSave}
|
|
45
42
|
onCancel={onCancel}
|
|
@@ -48,24 +45,21 @@ export const TriggerEditor = ({ space, trigger, readonlySpec, onSave, onCancel }
|
|
|
48
45
|
);
|
|
49
46
|
};
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
space,
|
|
53
|
-
readonlySpec,
|
|
54
|
-
onQueryRefOptions,
|
|
55
|
-
}: {
|
|
48
|
+
type UseCustomInputsProps = {
|
|
56
49
|
space: Space;
|
|
57
50
|
readonlySpec?: boolean;
|
|
58
51
|
onQueryRefOptions: FunctionInputEditorProps['onQueryRefOptions'];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
} & Pick<QueryFormProps, 'types' | 'tags'>;
|
|
53
|
+
|
|
54
|
+
const useCustomInputs = ({ space, readonlySpec, types, tags, onQueryRefOptions }: UseCustomInputsProps) => {
|
|
55
|
+
const functions = useQuery(space, Filter.type(Function.Function));
|
|
62
56
|
const workflows = useQuery(space, Filter.type(ComputeGraph));
|
|
63
|
-
const scripts = useQuery(space, Filter.type(
|
|
57
|
+
const scripts = useQuery(space, Filter.type(Script.Script));
|
|
64
58
|
|
|
65
59
|
return useMemo(
|
|
66
60
|
(): CustomInputMap => ({
|
|
67
61
|
// Function selector.
|
|
68
|
-
['function' satisfies keyof
|
|
62
|
+
['function' satisfies keyof Trigger.Trigger]: (props) => {
|
|
69
63
|
const getValue = useCallback(() => {
|
|
70
64
|
const formValue = props.getValue();
|
|
71
65
|
if (Ref.isRef(formValue)) {
|
|
@@ -76,7 +70,7 @@ const useCustomInputs = ({
|
|
|
76
70
|
|
|
77
71
|
const handleOnValueChange = useCallback(
|
|
78
72
|
(_type: any, dxnString: string) => {
|
|
79
|
-
const dxn =
|
|
73
|
+
const dxn = DXN.parse(dxnString);
|
|
80
74
|
if (dxn) {
|
|
81
75
|
const ref = Ref.fromDXN(dxn);
|
|
82
76
|
props.onValueChange('object', ref);
|
|
@@ -101,39 +95,15 @@ const useCustomInputs = ({
|
|
|
101
95
|
// TODO(wittjosiah): Copied from ViewEditor.
|
|
102
96
|
// Query input editor.
|
|
103
97
|
['spec.query' as const]: (props) => {
|
|
104
|
-
const { themeMode } = useThemeContext();
|
|
105
|
-
const density = useDensityContext();
|
|
106
|
-
const elevation = useElevationContext();
|
|
107
|
-
const value = props.getValue() as any;
|
|
108
|
-
|
|
109
|
-
// TODO(wittjosiah): Including props.onValueChange in deps causes infinite loop.
|
|
110
98
|
const handleChange = useCallback(
|
|
111
|
-
(
|
|
112
|
-
[],
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
const extensions = useMemo(
|
|
116
|
-
() => [
|
|
117
|
-
createBasicExtensions({ readOnly: readonlySpec, placeholder: t('query placeholder') }),
|
|
118
|
-
createThemeExtensions({ themeMode }),
|
|
119
|
-
],
|
|
120
|
-
[],
|
|
99
|
+
(query: Query.Any) => props.onValueChange('object', { ast: query.ast }),
|
|
100
|
+
[props.onValueChange],
|
|
121
101
|
);
|
|
122
102
|
|
|
123
|
-
// TODO(wittjosiah): This is probably not the right way to do these styles.
|
|
124
103
|
return (
|
|
125
104
|
<Input.Root>
|
|
126
105
|
<InputHeader label={props.label} />
|
|
127
|
-
<
|
|
128
|
-
classNames={mx(
|
|
129
|
-
inputTheme.input({ density, elevation }),
|
|
130
|
-
'flex items-center',
|
|
131
|
-
'focus-within:bg-focusSurface focus-within:border-separator focus-within:hover:bg-focusSurface',
|
|
132
|
-
)}
|
|
133
|
-
extensions={extensions}
|
|
134
|
-
value={value.string}
|
|
135
|
-
onChange={handleChange}
|
|
136
|
-
/>
|
|
106
|
+
<QueryForm initialQuery={(props.getValue() as any).ast} types={types} tags={tags} onChange={handleChange} />
|
|
137
107
|
</Input.Root>
|
|
138
108
|
);
|
|
139
109
|
},
|
|
@@ -151,7 +121,7 @@ const getWorkflowOptions = (graphs: ComputeGraph[]) => {
|
|
|
151
121
|
return graphs.map((graph) => ({ label: `compute-${graph.id}`, value: `dxn:echo:@:${graph.id}` }));
|
|
152
122
|
};
|
|
153
123
|
|
|
154
|
-
const getFunctionOptions = (scripts:
|
|
155
|
-
const getLabel = (fn:
|
|
124
|
+
const getFunctionOptions = (scripts: Script.Script[], functions: Function.Function[]) => {
|
|
125
|
+
const getLabel = (fn: Function.Function) => scripts.find((s) => fn.source?.target?.id === s.id)?.name ?? fn.name;
|
|
156
126
|
return functions.map((fn) => ({ label: getLabel(fn), value: `dxn:echo:@:${fn.id}` }));
|
|
157
127
|
};
|
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Cause from 'effect/Cause';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Exit from 'effect/Exit';
|
|
6
8
|
import { useCallback } from 'react';
|
|
7
9
|
|
|
8
|
-
import { useCapability } from '@dxos/app-framework';
|
|
10
|
+
import { useCapability } from '@dxos/app-framework/react';
|
|
11
|
+
import { type FunctionDefinition, FunctionInvocationService } from '@dxos/functions';
|
|
12
|
+
import { InvocationTracer, TracingServiceExt } from '@dxos/functions-runtime';
|
|
13
|
+
import { log } from '@dxos/log';
|
|
9
14
|
import type { Space } from '@dxos/react-client/echo';
|
|
10
15
|
|
|
11
16
|
import { AutomationCapabilities } from '../capabilities';
|
|
@@ -13,6 +18,7 @@ import { AutomationCapabilities } from '../capabilities';
|
|
|
13
18
|
/**
|
|
14
19
|
* Create an effectful function that has access to compute services
|
|
15
20
|
*/
|
|
21
|
+
// TODO(burdon): Factor out (figure out cross-plugin capabilities dependencies).
|
|
16
22
|
export const useComputeRuntimeCallback = <T>(
|
|
17
23
|
space: Space | undefined,
|
|
18
24
|
fn: () => Effect.Effect<T, any, AutomationCapabilities.ComputeServices>,
|
|
@@ -25,6 +31,38 @@ export const useComputeRuntimeCallback = <T>(
|
|
|
25
31
|
if (!runtime) {
|
|
26
32
|
throw new TypeError('Space not provided to useComputeRuntimeCallback');
|
|
27
33
|
}
|
|
34
|
+
|
|
28
35
|
return runtime.runPromise(fn());
|
|
29
36
|
}, [runtime, ...(deps ?? [])]);
|
|
30
37
|
};
|
|
38
|
+
|
|
39
|
+
// TODO(wittjosiah): Function invoking should automatically be traced (DX-647).
|
|
40
|
+
export const invokeFunctionWithTracing = <I, O>(functionDef: FunctionDefinition<I, O>, inputData: I) =>
|
|
41
|
+
Effect.gen(function* () {
|
|
42
|
+
const tracer = yield* InvocationTracer;
|
|
43
|
+
const trace = yield* tracer.traceInvocationStart({
|
|
44
|
+
target: undefined,
|
|
45
|
+
payload: {
|
|
46
|
+
data: {},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Invoke the function.
|
|
51
|
+
const result = yield* FunctionInvocationService.invokeFunction(functionDef, inputData).pipe(
|
|
52
|
+
Effect.provide(TracingServiceExt.layerQueue(trace.invocationTraceQueue)),
|
|
53
|
+
Effect.exit,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (Exit.isFailure(result)) {
|
|
57
|
+
const error = Cause.prettyErrors(result.cause)[0];
|
|
58
|
+
log.error(error.message, error.cause ?? error.stack);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
yield* tracer.traceInvocationEnd({
|
|
62
|
+
trace,
|
|
63
|
+
// TODO(dmaretskyi): Might miss errors.
|
|
64
|
+
exception: Exit.isFailure(result) ? Cause.prettyErrors(result.cause)[0] : undefined,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return result;
|
|
68
|
+
});
|
|
@@ -5,21 +5,22 @@
|
|
|
5
5
|
import * as Effect from 'effect/Effect';
|
|
6
6
|
|
|
7
7
|
import { Filter } from '@dxos/echo';
|
|
8
|
-
import {
|
|
8
|
+
import { Trigger } from '@dxos/functions';
|
|
9
|
+
import { TriggerDispatcher } from '@dxos/functions-runtime';
|
|
9
10
|
import { type Space, useQuery } from '@dxos/react-client/echo';
|
|
10
11
|
import { useAsyncState } from '@dxos/react-ui';
|
|
11
12
|
|
|
12
13
|
import { useComputeRuntimeCallback } from './useComputeRuntimeCallback';
|
|
13
14
|
|
|
14
15
|
interface TriggerRuntimeControls {
|
|
15
|
-
triggers:
|
|
16
|
+
triggers: Trigger.Trigger[];
|
|
16
17
|
isRunning: boolean;
|
|
17
18
|
start: () => void;
|
|
18
19
|
stop: () => void;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const useTriggerRuntimeControls = (space: Space | undefined): TriggerRuntimeControls => {
|
|
22
|
-
const triggers = useQuery(space, Filter.type(
|
|
23
|
+
const triggers = useQuery(space, Filter.type(Trigger.Trigger));
|
|
23
24
|
|
|
24
25
|
const [isRunningState, setIsRunningState] = useAsyncState(
|
|
25
26
|
useComputeRuntimeCallback(space, () => TriggerDispatcher.pipe(Effect.map((t) => t.running))),
|
package/src/index.ts
CHANGED
package/src/meta.ts
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type PluginMeta } from '@dxos/app-framework';
|
|
6
|
+
import { trim } from '@dxos/util';
|
|
6
7
|
|
|
7
8
|
export const meta: PluginMeta = {
|
|
8
9
|
id: 'dxos.org/plugin/automation',
|
|
9
10
|
name: 'Automation',
|
|
10
|
-
description:
|
|
11
|
-
|
|
11
|
+
description: trim`
|
|
12
|
+
Workflow automation engine that triggers custom actions based on object events and conditions.
|
|
13
|
+
Create automated pipelines that respond to changes and streamline repetitive tasks.
|
|
14
|
+
`,
|
|
12
15
|
icon: 'ph--robot--regular',
|
|
13
16
|
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-automation',
|
|
14
17
|
};
|