@dxos/plugin-automation 0.8.2-staging.7ac8446 → 0.8.3-main.672df60
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/AutomationContainer-HQK7FTN6.mjs +40 -0
- package/dist/lib/browser/AutomationContainer-HQK7FTN6.mjs.map +7 -0
- package/dist/lib/browser/AutomationPanel-GU37N5LO.mjs +11 -0
- package/dist/lib/browser/AutomationPanel-GU37N5LO.mjs.map +7 -0
- package/dist/lib/browser/FunctionsContainer-B7RDWVMX.mjs +39 -0
- package/dist/lib/browser/FunctionsContainer-B7RDWVMX.mjs.map +7 -0
- package/dist/lib/browser/FunctionsPanel-LCCPDIT6.mjs +10 -0
- package/dist/lib/browser/FunctionsPanel-LCCPDIT6.mjs.map +7 -0
- package/dist/lib/browser/app-graph-builder-BYECL42X.mjs +80 -0
- package/dist/lib/browser/app-graph-builder-BYECL42X.mjs.map +7 -0
- package/dist/lib/browser/chunk-4E2KPMLB.mjs +39 -0
- package/dist/lib/browser/chunk-4E2KPMLB.mjs.map +7 -0
- package/dist/lib/browser/chunk-4QTXMPBC.mjs +229 -0
- package/dist/lib/browser/chunk-4QTXMPBC.mjs.map +7 -0
- package/dist/lib/browser/chunk-D2ESAYQD.mjs +149 -0
- package/dist/lib/browser/chunk-D2ESAYQD.mjs.map +7 -0
- package/dist/lib/browser/chunk-ELQ2FX5G.mjs +14 -0
- package/dist/lib/browser/chunk-ELQ2FX5G.mjs.map +7 -0
- package/dist/lib/browser/{chunk-WKKQV4PC.mjs → chunk-IHAKPP5A.mjs} +2 -2
- package/dist/lib/browser/{chunk-WKKQV4PC.mjs.map → chunk-IHAKPP5A.mjs.map} +1 -1
- package/dist/lib/browser/chunk-ZTRYR6RJ.mjs +94 -0
- package/dist/lib/browser/chunk-ZTRYR6RJ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +26 -20
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/intent-resolver-ZRBBYZUX.mjs +77 -0
- package/dist/lib/browser/intent-resolver-ZRBBYZUX.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-surface-VKO6PA2P.mjs +68 -0
- package/dist/lib/browser/react-surface-VKO6PA2P.mjs.map +7 -0
- package/dist/lib/browser/types.mjs +8 -0
- package/dist/lib/browser/types.mjs.map +7 -0
- package/dist/lib/node/AutomationContainer-5J7LJK7L.cjs +68 -0
- package/dist/lib/node/AutomationContainer-5J7LJK7L.cjs.map +7 -0
- package/dist/lib/node/AutomationPanel-NPDBUQ7D.cjs +32 -0
- package/dist/lib/node/AutomationPanel-NPDBUQ7D.cjs.map +7 -0
- package/dist/lib/node/FunctionsContainer-LNLDZUZ6.cjs +67 -0
- package/dist/lib/node/FunctionsContainer-LNLDZUZ6.cjs.map +7 -0
- package/dist/lib/node/FunctionsPanel-7AOXIQMA.cjs +31 -0
- package/dist/lib/node/FunctionsPanel-7AOXIQMA.cjs.map +7 -0
- package/dist/lib/node/app-graph-builder-DUKR2BRB.cjs +96 -0
- package/dist/lib/node/app-graph-builder-DUKR2BRB.cjs.map +7 -0
- package/dist/lib/node/{chunk-7GXNXMSM.cjs → chunk-3EF7MLFX.cjs} +5 -5
- package/dist/lib/node/{chunk-7GXNXMSM.cjs.map → chunk-3EF7MLFX.cjs.map} +1 -1
- package/dist/lib/node/chunk-4O627QZU.cjs +175 -0
- package/dist/lib/node/chunk-4O627QZU.cjs.map +7 -0
- package/dist/lib/node/{chunk-AGJ6XTDN.cjs → chunk-DOLMQUQ5.cjs} +16 -7
- package/dist/lib/node/chunk-DOLMQUQ5.cjs.map +7 -0
- package/dist/lib/node/chunk-GIIVTK4O.cjs +58 -0
- package/dist/lib/node/chunk-GIIVTK4O.cjs.map +7 -0
- package/dist/lib/node/chunk-O42NQYQT.cjs +252 -0
- package/dist/lib/node/chunk-O42NQYQT.cjs.map +7 -0
- package/dist/lib/node/chunk-WXQAVUBJ.cjs +122 -0
- package/dist/lib/node/chunk-WXQAVUBJ.cjs.map +7 -0
- package/dist/lib/node/index.cjs +37 -31
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/intent-resolver-JC4Q4TYU.cjs +93 -0
- package/dist/lib/node/intent-resolver-JC4Q4TYU.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/{react-surface-52M54VWV.cjs → react-surface-HB3MYTCK.cjs} +41 -17
- package/dist/lib/node/react-surface-HB3MYTCK.cjs.map +7 -0
- package/dist/lib/node/types.cjs +30 -0
- package/dist/lib/node/types.cjs.map +7 -0
- package/dist/lib/node-esm/AutomationContainer-OJGH76X2.mjs +41 -0
- package/dist/lib/node-esm/AutomationContainer-OJGH76X2.mjs.map +7 -0
- package/dist/lib/node-esm/AutomationPanel-HIWEJUWL.mjs +12 -0
- package/dist/lib/node-esm/AutomationPanel-HIWEJUWL.mjs.map +7 -0
- package/dist/lib/node-esm/FunctionsContainer-PPR6XNNR.mjs +40 -0
- package/dist/lib/node-esm/FunctionsContainer-PPR6XNNR.mjs.map +7 -0
- package/dist/lib/node-esm/FunctionsPanel-SBXKWTHR.mjs +11 -0
- package/dist/lib/node-esm/FunctionsPanel-SBXKWTHR.mjs.map +7 -0
- package/dist/lib/node-esm/app-graph-builder-UAXHKKGW.mjs +81 -0
- package/dist/lib/node-esm/app-graph-builder-UAXHKKGW.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-5IAHBEHR.mjs +95 -0
- package/dist/lib/node-esm/chunk-5IAHBEHR.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-6JOJ2NN4.mjs +40 -0
- package/dist/lib/node-esm/chunk-6JOJ2NN4.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-D5HK4XLC.mjs +230 -0
- package/dist/lib/node-esm/chunk-D5HK4XLC.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-DZ44LGYT.mjs → chunk-HCCLRNMJ.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-DZ44LGYT.mjs.map → chunk-HCCLRNMJ.mjs.map} +1 -1
- package/dist/lib/node-esm/chunk-P2FKMPRE.mjs +150 -0
- package/dist/lib/node-esm/chunk-P2FKMPRE.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-Z7VAQDEE.mjs +16 -0
- package/dist/lib/node-esm/chunk-Z7VAQDEE.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +26 -20
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/intent-resolver-KRCXJEDR.mjs +78 -0
- package/dist/lib/node-esm/intent-resolver-KRCXJEDR.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/react-surface-TRKCIZAB.mjs +69 -0
- package/dist/lib/node-esm/react-surface-TRKCIZAB.mjs.map +7 -0
- package/dist/lib/node-esm/types.mjs +9 -0
- package/dist/lib/node-esm/types.mjs.map +7 -0
- package/dist/types/src/AutomationPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +2 -179
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +2 -177
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/AutomationContainer.d.ts +7 -0
- package/dist/types/src/components/AutomationContainer.d.ts.map +1 -0
- package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +6 -3
- package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +1 -1
- package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts.map +1 -1
- package/dist/types/src/components/AutomationPanel/index.d.ts +1 -0
- package/dist/types/src/components/AutomationPanel/index.d.ts.map +1 -1
- package/dist/types/src/components/FunctionsContainer.d.ts +7 -0
- package/dist/types/src/components/FunctionsContainer.d.ts.map +1 -0
- package/dist/types/src/components/FunctionsPanel/FunctionsPanel.d.ts +7 -0
- package/dist/types/src/components/FunctionsPanel/FunctionsPanel.d.ts.map +1 -0
- package/dist/types/src/components/FunctionsPanel/index.d.ts +4 -0
- package/dist/types/src/components/FunctionsPanel/index.d.ts.map +1 -0
- package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts +12 -0
- package/dist/types/src/components/TriggerEditor/FunctionInputEditor.d.ts.map +1 -0
- package/dist/types/src/components/TriggerEditor/SpecSelector.d.ts +5 -0
- package/dist/types/src/components/TriggerEditor/SpecSelector.d.ts.map +1 -0
- package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +1 -1
- package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
- package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +8 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-functions.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +8 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +25 -0
- package/dist/types/src/types.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +38 -25
- package/src/AutomationPlugin.tsx +5 -10
- package/src/capabilities/app-graph-builder.ts +72 -17
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/intent-resolver.ts +73 -0
- package/src/capabilities/react-surface.tsx +32 -8
- package/src/components/AutomationContainer.tsx +31 -0
- package/src/components/AutomationPanel/AutomationPanel.stories.tsx +6 -5
- package/src/components/AutomationPanel/AutomationPanel.tsx +77 -73
- package/src/components/AutomationPanel/index.ts +2 -0
- package/src/components/FunctionsContainer.tsx +31 -0
- package/src/components/FunctionsPanel/FunctionsPanel.tsx +95 -0
- package/src/components/FunctionsPanel/index.ts +8 -0
- package/src/components/TriggerEditor/FunctionInputEditor.tsx +77 -0
- package/src/components/TriggerEditor/SpecSelector.tsx +59 -0
- package/src/components/TriggerEditor/TriggerEditor.stories.tsx +19 -10
- package/src/components/TriggerEditor/TriggerEditor.tsx +64 -102
- package/src/components/index.ts +3 -0
- package/src/meta.ts +1 -1
- package/src/testing/test-functions.ts +23 -9
- package/src/translations.ts +10 -1
- package/src/types.ts +33 -0
- package/dist/lib/browser/AutomationPanel-YAHFXQX6.mjs +0 -139
- package/dist/lib/browser/AutomationPanel-YAHFXQX6.mjs.map +0 -7
- package/dist/lib/browser/app-graph-builder-K3BIQFWW.mjs +0 -40
- package/dist/lib/browser/app-graph-builder-K3BIQFWW.mjs.map +0 -7
- package/dist/lib/browser/chunk-FALBBJNO.mjs +0 -138
- package/dist/lib/browser/chunk-FALBBJNO.mjs.map +0 -7
- package/dist/lib/browser/chunk-MT3FZH4V.mjs +0 -8
- package/dist/lib/browser/chunk-MT3FZH4V.mjs.map +0 -7
- package/dist/lib/browser/react-surface-4QQSJR4A.mjs +0 -42
- package/dist/lib/browser/react-surface-4QQSJR4A.mjs.map +0 -7
- package/dist/lib/node/AutomationPanel-ZKAMIU6O.cjs +0 -161
- package/dist/lib/node/AutomationPanel-ZKAMIU6O.cjs.map +0 -7
- package/dist/lib/node/app-graph-builder-HO4FPGZ5.cjs +0 -56
- package/dist/lib/node/app-graph-builder-HO4FPGZ5.cjs.map +0 -7
- package/dist/lib/node/chunk-AGJ6XTDN.cjs.map +0 -7
- package/dist/lib/node/chunk-FTEDH5Q6.cjs +0 -167
- package/dist/lib/node/chunk-FTEDH5Q6.cjs.map +0 -7
- package/dist/lib/node/react-surface-52M54VWV.cjs.map +0 -7
- package/dist/lib/node-esm/AutomationPanel-XF7YPSKM.mjs +0 -140
- package/dist/lib/node-esm/AutomationPanel-XF7YPSKM.mjs.map +0 -7
- package/dist/lib/node-esm/app-graph-builder-XCJR33VS.mjs +0 -41
- package/dist/lib/node-esm/app-graph-builder-XCJR33VS.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-M4QXMIIB.mjs +0 -139
- package/dist/lib/node-esm/chunk-M4QXMIIB.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-OA75PSGH.mjs +0 -10
- package/dist/lib/node-esm/chunk-OA75PSGH.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-MGKM3OO3.mjs +0 -43
- package/dist/lib/node-esm/react-surface-MGKM3OO3.mjs.map +0 -7
|
@@ -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
|
|
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
|
|
11
|
-
import {
|
|
10
|
+
import { FunctionType, FunctionTrigger, TriggerKind } from '@dxos/functions';
|
|
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(
|
|
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='
|
|
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
|
-
space.db.add(
|
|
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,
|
|
68
|
+
withLayout({ fullscreen: true, classNames: 'flex justify-center m-2' }),
|
|
60
69
|
withTheme,
|
|
61
70
|
],
|
|
62
71
|
parameters: {
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { useCallback,
|
|
5
|
+
import React, { useCallback, useMemo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { ComputeGraph } from '@dxos/conductor';
|
|
8
|
+
import { Type } from '@dxos/echo';
|
|
8
9
|
import {
|
|
9
10
|
FunctionType,
|
|
10
11
|
FunctionTriggerSchema,
|
|
11
12
|
type FunctionTriggerType,
|
|
12
13
|
type FunctionTrigger,
|
|
13
14
|
ScriptType,
|
|
14
|
-
|
|
15
|
-
} from '@dxos/
|
|
16
|
-
import {
|
|
17
|
-
import { IconButton, Input, useTranslation } from '@dxos/react-ui';
|
|
18
|
-
import { type CustomInputMap, Form, type InputProps, SelectInput, TextInput, useInputProps } from '@dxos/react-ui-form';
|
|
15
|
+
} from '@dxos/functions';
|
|
16
|
+
import { Filter, Ref, useQuery, type Space } from '@dxos/react-client/echo';
|
|
17
|
+
import { type CustomInputMap, Form, SelectInput, useRefQueryLookupHandler } from '@dxos/react-ui-form';
|
|
19
18
|
|
|
20
|
-
import {
|
|
19
|
+
import { FunctionInputEditor, type FunctionInputEditorProps } from './FunctionInputEditor';
|
|
20
|
+
import { SpecSelector } from './SpecSelector';
|
|
21
21
|
|
|
22
22
|
export type TriggerEditorProps = {
|
|
23
23
|
space: Space;
|
|
@@ -26,119 +26,81 @@ export type TriggerEditorProps = {
|
|
|
26
26
|
onCancel?: () => void;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
const PayloadInput = (props: InputProps & { property: string }) => {
|
|
30
|
-
const { t } = useTranslation(AUTOMATION_PLUGIN);
|
|
31
|
-
// TODO(dmaretskyi): Prop name (`meta`) should be passed in.
|
|
32
|
-
const inputProps = useInputProps(['meta', props.property]);
|
|
33
|
-
return (
|
|
34
|
-
<div role='none' className='flex items-center mt-2 gap-1'>
|
|
35
|
-
<div role='none' className='flex-1'>
|
|
36
|
-
<TextInput {...inputProps} type='string' label={props.property} />
|
|
37
|
-
</div>
|
|
38
|
-
<IconButton
|
|
39
|
-
icon='ph--trash--regular'
|
|
40
|
-
iconOnly
|
|
41
|
-
classNames={'mt-6'}
|
|
42
|
-
label={t('trigger meta remove')}
|
|
43
|
-
onClick={() => {
|
|
44
|
-
const newValues: any = { ...props.getValue() };
|
|
45
|
-
delete newValues[props.property];
|
|
46
|
-
props.onValueChange('object', newValues);
|
|
47
|
-
}}
|
|
48
|
-
/>
|
|
49
|
-
</div>
|
|
50
|
-
);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
29
|
export const TriggerEditor = ({ space, trigger, onSave, onCancel }: TriggerEditorProps) => {
|
|
54
|
-
const { t } = useTranslation(AUTOMATION_PLUGIN);
|
|
55
|
-
|
|
56
|
-
const functions = useQuery(space, Filter.schema(FunctionType));
|
|
57
|
-
const workflows = useQuery(space, Filter.schema(ComputeGraph));
|
|
58
|
-
const scripts = useQuery(space, Filter.schema(ScriptType));
|
|
59
|
-
|
|
60
30
|
const handleSave = (values: FunctionTriggerType) => {
|
|
61
31
|
onSave?.(values);
|
|
62
32
|
};
|
|
63
33
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
['function' satisfies keyof FunctionTriggerType]: (props) => (
|
|
67
|
-
<SelectInput
|
|
68
|
-
{...props}
|
|
69
|
-
options={getWorkflowOptions(workflows).concat(getFunctionOptions(scripts, functions))}
|
|
70
|
-
/>
|
|
71
|
-
),
|
|
72
|
-
['spec.type' as const]: (props) => (
|
|
73
|
-
<SelectInput
|
|
74
|
-
{...props}
|
|
75
|
-
options={Object.values(TriggerKind).map((kind) => ({
|
|
76
|
-
value: kind,
|
|
77
|
-
label: t(`trigger type ${kind}`),
|
|
78
|
-
}))}
|
|
79
|
-
/>
|
|
80
|
-
),
|
|
81
|
-
// TODO(wittjosiah): Form should be able to handle arbitrary records by default.
|
|
82
|
-
['meta' as const]: (props) => {
|
|
83
|
-
const payload = props.getValue() ?? {};
|
|
84
|
-
useEffect(() => props.onValueChange('object', { ...payload }), []);
|
|
85
|
-
const [newPayloadFieldName, setNewPayloadFieldName] = useState('');
|
|
86
|
-
|
|
87
|
-
const handleAddPayload = useCallback(() => {
|
|
88
|
-
if (newPayloadFieldName.length) {
|
|
89
|
-
const payload = props.getValue() ?? {};
|
|
90
|
-
const payloadWithNewProp = { ...payload, [newPayloadFieldName]: '' };
|
|
91
|
-
setNewPayloadFieldName('');
|
|
92
|
-
props.onValueChange('object', payloadWithNewProp);
|
|
93
|
-
}
|
|
94
|
-
}, [newPayloadFieldName, props.getValue, props.onValueChange]);
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<>
|
|
98
|
-
<div>{/* TODO(wittjosiah): props.label */ 'Payload'}</div>
|
|
99
|
-
{[...Object.keys(payload)].map((key) => (
|
|
100
|
-
<PayloadInput key={key} property={key} {...props} />
|
|
101
|
-
))}
|
|
102
|
-
<div role='none' className='flex items-center mt-2 gap-1 plb-1'>
|
|
103
|
-
<div role='none' className='flex-1'>
|
|
104
|
-
<Input.Root>
|
|
105
|
-
<Input.TextInput
|
|
106
|
-
placeholder={t('trigger payload prop name placeholder')}
|
|
107
|
-
value={newPayloadFieldName}
|
|
108
|
-
onChange={(event) => setNewPayloadFieldName(event.target.value)}
|
|
109
|
-
/>
|
|
110
|
-
</Input.Root>
|
|
111
|
-
</div>
|
|
112
|
-
<IconButton
|
|
113
|
-
icon='ph--plus--regular'
|
|
114
|
-
iconOnly
|
|
115
|
-
label={t('trigger payload add')}
|
|
116
|
-
onClick={handleAddPayload}
|
|
117
|
-
/>
|
|
118
|
-
</div>
|
|
119
|
-
</>
|
|
120
|
-
);
|
|
121
|
-
},
|
|
122
|
-
}),
|
|
123
|
-
[workflows, scripts, functions, t],
|
|
124
|
-
);
|
|
34
|
+
const handleRefQueryLookup = useRefQueryLookupHandler({ space });
|
|
35
|
+
const Custom = useCustomInputs(space, handleRefQueryLookup);
|
|
125
36
|
|
|
126
37
|
return (
|
|
127
|
-
<Form
|
|
38
|
+
<Form
|
|
39
|
+
Custom={Custom}
|
|
128
40
|
schema={FunctionTriggerSchema}
|
|
129
41
|
values={trigger}
|
|
130
42
|
onSave={handleSave}
|
|
131
43
|
onCancel={onCancel}
|
|
132
|
-
|
|
44
|
+
onQueryRefOptions={handleRefQueryLookup}
|
|
133
45
|
/>
|
|
134
46
|
);
|
|
135
47
|
};
|
|
136
48
|
|
|
49
|
+
const useCustomInputs = (space: Space, onQueryRefOptions: FunctionInputEditorProps['onQueryRefOptions']) => {
|
|
50
|
+
const functions = useQuery(space, Filter.type(FunctionType));
|
|
51
|
+
const workflows = useQuery(space, Filter.type(ComputeGraph));
|
|
52
|
+
const scripts = useQuery(space, Filter.type(ScriptType));
|
|
53
|
+
|
|
54
|
+
return useMemo(
|
|
55
|
+
(): CustomInputMap => ({
|
|
56
|
+
// Function selector.
|
|
57
|
+
['function' satisfies keyof FunctionTriggerType]: (props) => {
|
|
58
|
+
const getValue = useCallback(() => {
|
|
59
|
+
const formValue = props.getValue();
|
|
60
|
+
if (Ref.isRef(formValue)) {
|
|
61
|
+
return formValue.dxn.toString() as string;
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}, [props]);
|
|
65
|
+
|
|
66
|
+
const handleOnValueChange = useCallback(
|
|
67
|
+
(_type: any, dxnString: string) => {
|
|
68
|
+
const dxn = Type.DXN.parse(dxnString);
|
|
69
|
+
if (dxn) {
|
|
70
|
+
const ref = Ref.fromDXN(dxn);
|
|
71
|
+
props.onValueChange('object', ref);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
[props.onValueChange],
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<SelectInput
|
|
79
|
+
{...props}
|
|
80
|
+
getValue={getValue as any}
|
|
81
|
+
onValueChange={handleOnValueChange}
|
|
82
|
+
options={getWorkflowOptions(workflows).concat(getFunctionOptions(scripts, functions))}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
// Spec selector.
|
|
88
|
+
['spec.kind' as const]: SpecSelector,
|
|
89
|
+
|
|
90
|
+
// Function input editor.
|
|
91
|
+
['input' as const]: (props) => (
|
|
92
|
+
<FunctionInputEditor {...props} functions={functions} onQueryRefOptions={onQueryRefOptions} />
|
|
93
|
+
),
|
|
94
|
+
}),
|
|
95
|
+
[workflows, scripts, functions],
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
137
99
|
const getWorkflowOptions = (graphs: ComputeGraph[]) => {
|
|
138
100
|
return graphs.map((graph) => ({ label: `compute-${graph.id}`, value: `dxn:echo:@:${graph.id}` }));
|
|
139
101
|
};
|
|
140
102
|
|
|
141
103
|
const getFunctionOptions = (scripts: ScriptType[], functions: FunctionType[]) => {
|
|
142
104
|
const getLabel = (fn: FunctionType) => scripts.find((s) => fn.source?.target?.id === s.id)?.name ?? fn.name;
|
|
143
|
-
return functions.map((fn) => ({ label: getLabel(fn), value: `dxn:
|
|
105
|
+
return functions.map((fn) => ({ label: getLabel(fn), value: `dxn:echo:@:${fn.id}` }));
|
|
144
106
|
};
|
package/src/components/index.ts
CHANGED
|
@@ -6,4 +6,7 @@ import { lazy } from 'react';
|
|
|
6
6
|
|
|
7
7
|
export * from './TriggerEditor';
|
|
8
8
|
|
|
9
|
+
export const AutomationContainer = lazy(() => import('./AutomationContainer'));
|
|
9
10
|
export const AutomationPanel = lazy(() => import('./AutomationPanel'));
|
|
11
|
+
export const FunctionsContainer = lazy(() => import('./FunctionsContainer'));
|
|
12
|
+
export const FunctionsPanel = lazy(() => import('./FunctionsPanel'));
|
package/src/meta.ts
CHANGED
|
@@ -12,5 +12,5 @@ export const meta: PluginMeta = {
|
|
|
12
12
|
description:
|
|
13
13
|
'The Automation tab allows you to trigger pre-defined workflows related to the element you are interacting with inside of Composer.',
|
|
14
14
|
icon: 'ph--robot--regular',
|
|
15
|
-
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/
|
|
15
|
+
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-automation',
|
|
16
16
|
};
|
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
|
+
|
|
7
|
+
import { ContactType } from '@dxos/client/testing';
|
|
8
|
+
import { Ref, toJsonSchema } from '@dxos/echo-schema';
|
|
6
9
|
|
|
7
10
|
export const functions = [
|
|
8
11
|
{
|
|
9
12
|
name: 'example.com/function/chess',
|
|
10
13
|
version: '0.1.0',
|
|
11
14
|
inputSchema: toJsonSchema(
|
|
12
|
-
|
|
13
|
-
level:
|
|
14
|
-
|
|
15
|
+
Schema.Struct({
|
|
16
|
+
level: Schema.Number.annotations({
|
|
17
|
+
title: 'Level',
|
|
15
18
|
}),
|
|
16
19
|
}),
|
|
17
20
|
),
|
|
@@ -21,12 +24,23 @@ export const functions = [
|
|
|
21
24
|
version: '0.1.0',
|
|
22
25
|
binding: 'FOREX',
|
|
23
26
|
inputSchema: toJsonSchema(
|
|
24
|
-
|
|
25
|
-
from:
|
|
26
|
-
|
|
27
|
+
Schema.Struct({
|
|
28
|
+
from: Schema.String.annotations({
|
|
29
|
+
title: 'Currency from',
|
|
30
|
+
}),
|
|
31
|
+
to: Schema.String.annotations({
|
|
32
|
+
title: 'Currency to',
|
|
27
33
|
}),
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'example.com/function/ping-contact',
|
|
39
|
+
version: '0.0.1',
|
|
40
|
+
inputSchema: toJsonSchema(
|
|
41
|
+
Schema.Struct({
|
|
42
|
+
contact: Ref(ContactType).annotations({
|
|
43
|
+
title: 'Contact',
|
|
30
44
|
}),
|
|
31
45
|
}),
|
|
32
46
|
),
|
package/src/translations.ts
CHANGED
|
@@ -11,8 +11,17 @@ export default [
|
|
|
11
11
|
'plugin name': 'Automation',
|
|
12
12
|
'automation panel label': 'Automations',
|
|
13
13
|
'script automation label': 'Automation',
|
|
14
|
+
'automation verbose label': 'Manage automations',
|
|
15
|
+
'automation description': 'You can manage all the triggers which automate your space here.',
|
|
14
16
|
|
|
15
|
-
'
|
|
17
|
+
'functions panel label': 'Functions',
|
|
18
|
+
'functions verbose label': 'Manage deployed functions',
|
|
19
|
+
'functions description': 'You can manage all the functions deployed from your space on EDGE here.',
|
|
20
|
+
'function copy id': 'Copy Function ID',
|
|
21
|
+
'no functions found': 'No functions found',
|
|
22
|
+
'go to function source button label': 'Show function source',
|
|
23
|
+
|
|
24
|
+
'trigger editor title': 'Configure Trigger',
|
|
16
25
|
'new trigger label': 'Add Trigger',
|
|
17
26
|
'trigger type timer': 'Timer',
|
|
18
27
|
'trigger type webhook': 'Webhook',
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
|
+
|
|
7
|
+
import { SpaceSchema } from '@dxos/react-client/echo';
|
|
8
|
+
|
|
9
|
+
import { AUTOMATION_PLUGIN } from './meta';
|
|
10
|
+
|
|
11
|
+
const TriggerTemplate = Schema.Union(
|
|
12
|
+
Schema.Struct({ type: Schema.Literal('timer'), cron: Schema.String }),
|
|
13
|
+
Schema.Struct({ type: Schema.Literal('queue'), queueDXN: Schema.Any }),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export namespace AutomationAction {
|
|
17
|
+
const AUTOMATION_ACTION = `${AUTOMATION_PLUGIN}/action`;
|
|
18
|
+
|
|
19
|
+
export class CreateTriggerFromTemplate extends Schema.TaggedClass<CreateTriggerFromTemplate>()(
|
|
20
|
+
`${AUTOMATION_ACTION}/create-trigger-from-template`,
|
|
21
|
+
{
|
|
22
|
+
input: Schema.Struct({
|
|
23
|
+
space: SpaceSchema,
|
|
24
|
+
template: TriggerTemplate,
|
|
25
|
+
enabled: Schema.optional(Schema.Boolean),
|
|
26
|
+
// TODO(wittjosiah): Improve how this lookup is done.
|
|
27
|
+
scriptName: Schema.optional(Schema.String),
|
|
28
|
+
input: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
|
|
29
|
+
}),
|
|
30
|
+
output: Schema.Void,
|
|
31
|
+
},
|
|
32
|
+
) {}
|
|
33
|
+
}
|