@dxos/plugin-automation 0.7.2-main.f1adc9f → 0.7.2

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 (87) hide show
  1. package/dist/lib/browser/{chunk-R6GS7UA7.mjs → chunk-B3Z4NQC2.mjs} +8 -2
  2. package/dist/lib/browser/{chunk-R6GS7UA7.mjs.map → chunk-B3Z4NQC2.mjs.map} +3 -3
  3. package/dist/lib/browser/{chunk-X5KMOH3I.mjs → chunk-PQLGYMNY.mjs} +2 -2
  4. package/dist/lib/browser/{chunk-X5KMOH3I.mjs.map → chunk-PQLGYMNY.mjs.map} +1 -1
  5. package/dist/lib/browser/index.mjs +286 -109
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/meta.mjs +1 -1
  9. package/dist/lib/browser/types/index.mjs +2 -1
  10. package/dist/lib/node/{chunk-DTJ7XVO2.cjs → chunk-JSZ6PAYL.cjs} +5 -5
  11. package/dist/lib/node/{chunk-DTJ7XVO2.cjs.map → chunk-JSZ6PAYL.cjs.map} +1 -1
  12. package/dist/lib/node/{chunk-JHKEVE65.cjs → chunk-SUMUWFZA.cjs} +8 -5
  13. package/dist/lib/node/{chunk-JHKEVE65.cjs.map → chunk-SUMUWFZA.cjs.map} +3 -3
  14. package/dist/lib/node/index.cjs +313 -143
  15. package/dist/lib/node/index.cjs.map +4 -4
  16. package/dist/lib/node/meta.cjs +3 -3
  17. package/dist/lib/node/meta.cjs.map +1 -1
  18. package/dist/lib/node/meta.json +1 -1
  19. package/dist/lib/node/types/index.cjs +7 -6
  20. package/dist/lib/node/types/index.cjs.map +2 -2
  21. package/dist/lib/node-esm/{chunk-HNOBZHWK.mjs → chunk-B35UD3D7.mjs} +2 -2
  22. package/dist/lib/node-esm/{chunk-HNOBZHWK.mjs.map → chunk-B35UD3D7.mjs.map} +1 -1
  23. package/dist/lib/node-esm/{chunk-ISJZVA2J.mjs → chunk-PYT2WY4B.mjs} +7 -2
  24. package/dist/lib/node-esm/{chunk-ISJZVA2J.mjs.map → chunk-PYT2WY4B.mjs.map} +3 -3
  25. package/dist/lib/node-esm/index.mjs +286 -109
  26. package/dist/lib/node-esm/index.mjs.map +4 -4
  27. package/dist/lib/node-esm/meta.json +1 -1
  28. package/dist/lib/node-esm/meta.mjs +1 -1
  29. package/dist/lib/node-esm/types/index.mjs +2 -1
  30. package/dist/types/src/AutomationPlugin.d.ts.map +1 -1
  31. package/dist/types/src/components/AutomationPanel.d.ts +3 -0
  32. package/dist/types/src/components/AutomationPanel.d.ts.map +1 -0
  33. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +2 -4
  34. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -1
  35. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -1
  36. package/dist/types/src/components/index.d.ts +3 -2
  37. package/dist/types/src/components/index.d.ts.map +1 -1
  38. package/dist/types/src/translations.d.ts +0 -2
  39. package/dist/types/src/translations.d.ts.map +1 -1
  40. package/dist/types/src/types/schema.d.ts +3 -3
  41. package/dist/types/src/types/types.d.ts +1 -0
  42. package/dist/types/src/types/types.d.ts.map +1 -1
  43. package/package.json +34 -37
  44. package/src/AutomationPlugin.tsx +35 -88
  45. package/src/components/AutomationPanel.tsx +23 -0
  46. package/src/components/TriggerEditor/TriggerEditor.stories.tsx +32 -2
  47. package/src/components/TriggerEditor/TriggerEditor.tsx +43 -9
  48. package/src/components/index.ts +3 -4
  49. package/src/meta.ts +1 -1
  50. package/src/translations.ts +0 -3
  51. package/src/types/types.ts +5 -3
  52. package/dist/lib/browser/AssistantPanel-622FK3DP.mjs +0 -341
  53. package/dist/lib/browser/AssistantPanel-622FK3DP.mjs.map +0 -7
  54. package/dist/lib/browser/AutomationPanel-PVI2EJNE.mjs +0 -125
  55. package/dist/lib/browser/AutomationPanel-PVI2EJNE.mjs.map +0 -7
  56. package/dist/lib/node/AssistantPanel-HRJRVOZD.cjs +0 -361
  57. package/dist/lib/node/AssistantPanel-HRJRVOZD.cjs.map +0 -7
  58. package/dist/lib/node/AutomationPanel-Z2XW24BN.cjs +0 -145
  59. package/dist/lib/node/AutomationPanel-Z2XW24BN.cjs.map +0 -7
  60. package/dist/lib/node-esm/AssistantPanel-QIIX7S4V.mjs +0 -342
  61. package/dist/lib/node-esm/AssistantPanel-QIIX7S4V.mjs.map +0 -7
  62. package/dist/lib/node-esm/AutomationPanel-5L5NFVKU.mjs +0 -126
  63. package/dist/lib/node-esm/AutomationPanel-5L5NFVKU.mjs.map +0 -7
  64. package/dist/types/src/components/AssistantPanel/AssistantPanel.d.ts +0 -8
  65. package/dist/types/src/components/AssistantPanel/AssistantPanel.d.ts.map +0 -1
  66. package/dist/types/src/components/AssistantPanel/index.d.ts +0 -3
  67. package/dist/types/src/components/AssistantPanel/index.d.ts.map +0 -1
  68. package/dist/types/src/components/AssistantPanel/system-instructions.d.ts +0 -6
  69. package/dist/types/src/components/AssistantPanel/system-instructions.d.ts.map +0 -1
  70. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +0 -9
  71. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +0 -1
  72. package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts +0 -6
  73. package/dist/types/src/components/AutomationPanel/AutomationPanel.stories.d.ts.map +0 -1
  74. package/dist/types/src/components/AutomationPanel/index.d.ts +0 -3
  75. package/dist/types/src/components/AutomationPanel/index.d.ts.map +0 -1
  76. package/dist/types/src/testing/index.d.ts +0 -2
  77. package/dist/types/src/testing/index.d.ts.map +0 -1
  78. package/dist/types/src/testing/testing.d.ts +0 -12
  79. package/dist/types/src/testing/testing.d.ts.map +0 -1
  80. package/src/components/AssistantPanel/AssistantPanel.tsx +0 -230
  81. package/src/components/AssistantPanel/index.ts +0 -7
  82. package/src/components/AssistantPanel/system-instructions.ts +0 -166
  83. package/src/components/AutomationPanel/AutomationPanel.stories.tsx +0 -57
  84. package/src/components/AutomationPanel/AutomationPanel.tsx +0 -96
  85. package/src/components/AutomationPanel/index.ts +0 -7
  86. package/src/testing/index.ts +0 -5
  87. package/src/testing/testing.ts +0 -34
@@ -1 +0,0 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../../src/testing/testing.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,SAAS;;;;;;;;;;IA2BrB,CAAC"}
@@ -1,230 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- /* eslint-disable no-console */
6
-
7
- import React, { useEffect, useRef, useState } from 'react';
8
-
9
- import { type AIServiceClient, AIServiceClientImpl, ObjectId, type Message } from '@dxos/assistant';
10
- import type { ReactiveEchoObject } from '@dxos/echo-db';
11
- import { SpaceId } from '@dxos/keys';
12
- import { useClient, useConfig } from '@dxos/react-client';
13
- import { ContextMenu, type ThemedClassName } from '@dxos/react-ui';
14
- import { Icon, Input, Toolbar, useTranslation } from '@dxos/react-ui';
15
- import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
16
- import { mx } from '@dxos/react-ui-theme';
17
-
18
- import { createSystemInstructions } from './system-instructions';
19
- import { AUTOMATION_PLUGIN } from '../../meta';
20
-
21
- const PROPERTIES_ASSISTANT_KEY = 'dxos.assistant.beta.properties';
22
-
23
- export type AssistantPanelProps = ThemedClassName<{
24
- subject?: ReactiveEchoObject<any>;
25
- }>;
26
-
27
- export const AssistantPanel = ({ subject, classNames }: AssistantPanelProps) => {
28
- const { t } = useTranslation(AUTOMATION_PLUGIN);
29
- const config = useConfig();
30
- const client = useClient();
31
- const aiClient = useRef<AIServiceClient>();
32
- const [contextSpaceId, setContextSpaceId] = useState<SpaceId | undefined>();
33
- const [threadId, setThreadId] = useState<ObjectId | undefined>();
34
- const [history, setHistory] = useState<Message[]>([]);
35
- const [input, setInput] = useState('');
36
-
37
- useEffect(() => {
38
- if (!aiClient.current) {
39
- const endpoint = config.values.runtime?.services?.ai?.server;
40
- if (!endpoint) {
41
- throw new Error('AI service endpoint is not configured');
42
- }
43
- aiClient.current = new AIServiceClientImpl({
44
- endpoint,
45
- });
46
- }
47
-
48
- queueMicrotask(async () => {
49
- const properties = client.spaces.default.properties;
50
-
51
- properties[PROPERTIES_ASSISTANT_KEY] ??= {};
52
- properties[PROPERTIES_ASSISTANT_KEY].contextSpaceId ??= SpaceId.random();
53
- properties[PROPERTIES_ASSISTANT_KEY].threadId ??= ObjectId.random();
54
-
55
- const contextSpaceId = properties[PROPERTIES_ASSISTANT_KEY].contextSpaceId;
56
- const threadId = properties[PROPERTIES_ASSISTANT_KEY].threadId;
57
-
58
- setContextSpaceId(contextSpaceId);
59
- setThreadId(threadId);
60
-
61
- const messages = await aiClient.current!.getMessagesInThread(contextSpaceId, threadId);
62
- setHistory(messages);
63
- });
64
- }, []);
65
-
66
- const handleRequest = async (input: string) => {
67
- if (input === '') {
68
- return;
69
- }
70
-
71
- setInput('');
72
-
73
- // TODO(dmaretskyi): Can we call `create(Message, { ... })` here?
74
- const userMessage: Message = {
75
- id: ObjectId.random(),
76
- spaceId: contextSpaceId!,
77
- threadId: threadId!,
78
- role: 'user',
79
- content: [{ type: 'text', text: input }],
80
- };
81
- await aiClient.current!.insertMessages([userMessage]);
82
- setHistory([...history, userMessage]);
83
-
84
- const generationStream = await aiClient.current!.generate({
85
- model: '@anthropic/claude-3-5-sonnet-20241022',
86
- spaceId: contextSpaceId!,
87
- threadId: threadId!,
88
- tools: [],
89
- systemPrompt: await getSystemPrompt(),
90
- });
91
-
92
- const historyBefore = [...history, userMessage];
93
- for await (const _event of generationStream) {
94
- setHistory([...historyBefore, ...generationStream.accumulatedMessages]);
95
- }
96
-
97
- await aiClient.current!.insertMessages(await generationStream.complete());
98
- };
99
-
100
- const getSystemPrompt = async () => {
101
- return createSystemInstructions({ subject });
102
- };
103
-
104
- const clearThread = async () => {
105
- const properties = client.spaces.default.properties;
106
-
107
- properties[PROPERTIES_ASSISTANT_KEY] ??= {};
108
- // properties[PROPERTIES_ASSISTANT_KEY].contextSpaceId ??= SpaceId.random();
109
- properties[PROPERTIES_ASSISTANT_KEY].threadId = ObjectId.random();
110
-
111
- // const contextSpaceId = properties[PROPERTIES_ASSISTANT_KEY].contextSpaceId;
112
- const threadId = properties[PROPERTIES_ASSISTANT_KEY].threadId;
113
-
114
- // setContextSpaceId(contextSpaceId);
115
- setThreadId(threadId);
116
-
117
- const messages = await aiClient.current!.getMessagesInThread(contextSpaceId!, threadId);
118
- setHistory(messages);
119
- };
120
-
121
- // TODO(burdon): Factor out with script plugin.
122
- return (
123
- <div className={mx('flex flex-col h-full overflow-hidden', classNames)}>
124
- {history.length > 0 && (
125
- <div className='flex flex-col gap-6 h-full p-2 overflow-x-hidden overflow-y-auto'>
126
- {history.map((message) => (
127
- <MessageItem key={message.id} message={message} />
128
- ))}
129
- </div>
130
- )}
131
-
132
- <Toolbar.Root classNames='p-1'>
133
- <Input.Root>
134
- <Input.TextInput
135
- autoFocus
136
- placeholder={t('ask me anything')}
137
- value={input}
138
- onChange={(ev) => setInput(ev.target.value)}
139
- onKeyDown={(ev) => ev.key === 'Enter' && handleRequest(input)}
140
- />
141
- </Input.Root>
142
- <ContextMenu.Root>
143
- <ContextMenu.Trigger asChild>
144
- <Toolbar.Button onClick={() => handleRequest(input)}>
145
- <Icon icon='ph--play--regular' size={4} />
146
- </Toolbar.Button>
147
- </ContextMenu.Trigger>
148
- <ContextMenu.Portal>
149
- <ContextMenu.Content classNames='z-[31]'>
150
- <ContextMenu.Viewport>
151
- <ContextMenu.Item onClick={clearThread}>Clear thread</ContextMenu.Item>
152
- <ContextMenu.Item onClick={async () => console.log(await getSystemPrompt())}>
153
- Print instructions to console
154
- </ContextMenu.Item>
155
- </ContextMenu.Viewport>
156
- </ContextMenu.Content>
157
- </ContextMenu.Portal>
158
- </ContextMenu.Root>
159
-
160
- {/* <Toolbar.Button onClick={() => (state ? handleStop() : handleClear())}>
161
- <Icon icon={state ? 'ph--stop--regular' : 'ph--trash--regular'} size={4} />
162
- </Toolbar.Button> */}
163
- </Toolbar.Root>
164
- </div>
165
- );
166
- };
167
-
168
- const MessageItem = ({ classNames, message }: ThemedClassName<{ message: Message }>) => {
169
- const { id: _, role, content } = message;
170
- const styleContainer = 'flex flex-col overflow-x-hidden overflow-y-auto rounded-md gap-2 divide-y divide-separator';
171
-
172
- return (
173
- <div className={mx('flex', role === 'user' ? 'ml-[1rem] justify-end' : 'mr-[1rem]', classNames)}>
174
- {content.map((content, i) => {
175
- switch (content.type) {
176
- case 'text': {
177
- const { cot, message } = parseMessage(content.text);
178
- return (
179
- <div
180
- key={i}
181
- role='none'
182
- className={mx(
183
- styleContainer,
184
- role === 'user' ? 'bg-primary-400 dark:bg-primary-600' : 'bg-hoverSurface',
185
- )}
186
- >
187
- {cot && <div className='p-2 whitespace-pre-wrap text-xs text-subdued'>{cot}</div>}
188
- <div className='p-2 whitespace-pre-wrap'>{message}</div>
189
- </div>
190
- );
191
- }
192
-
193
- case 'tool_use': {
194
- return (
195
- <div key={i} className={mx(styleContainer, 'text-xs')}>
196
- <div>
197
- <span className='p-2 text-primary'>Tool use</span>: {content.name} {content.id}
198
- </div>
199
- <SyntaxHighlighter language='json'>{content.inputJson}</SyntaxHighlighter>
200
- </div>
201
- );
202
- }
203
-
204
- case 'tool_result': {
205
- return (
206
- <div key={i} className={mx(styleContainer, 'text-xs', content.isError && 'text-error')}>
207
- <div>
208
- <span className='p-2 text-primary'>Tool result</span>: {content.toolUseId}
209
- </div>
210
- <SyntaxHighlighter language='json'>{content.content}</SyntaxHighlighter>
211
- </div>
212
- );
213
- }
214
- }
215
-
216
- return null;
217
- })}
218
- </div>
219
- );
220
- };
221
-
222
- // TODO(burdon): Move to server-side parsing.
223
- const parseMessage = (text: string): { cot?: string; message: string } => {
224
- const regex = /<cot>([\s\S]*?)<\/cot>\s*([\s\S]*)/;
225
- const match = text.match(regex);
226
- return {
227
- cot: match?.[1].trim(),
228
- message: match?.[2] ?? text ?? '\u00D8',
229
- };
230
- };
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { AssistantPanel } from './AssistantPanel';
6
-
7
- export default AssistantPanel;
@@ -1,166 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { asyncTimeout } from '@dxos/async';
6
- import type { ReactiveEchoObject } from '@dxos/echo-db';
7
- import { getTypename } from '@dxos/echo-schema';
8
- import { log } from '@dxos/log';
9
- import { Filter, getSpace, ResultFormat } from '@dxos/react-client/echo';
10
-
11
- // TODO(burdon): Move into assistant-protocol.
12
- export type ThreadContext = {
13
- subject?: ReactiveEchoObject<any>;
14
- };
15
-
16
- export const createSystemInstructions = async (context: ThreadContext): Promise<string> => {
17
- let instructions = `
18
- <instructions>
19
- Before replying always think step-by-step on how to proceed.
20
- Print your thoughts inside <cot> tags.
21
-
22
- <example>
23
- <cot>To answer the question I need to ...</cot>
24
- </example>
25
- </instructions>
26
-
27
- <current_time>${new Date().toLocaleString()}</current_time>
28
- `;
29
-
30
- if (context.subject) {
31
- instructions += `
32
- <user_attention>
33
- The user is currently interacting with an object in Composer application:
34
-
35
- ${await formatContextObject(context.subject)}
36
- </user_attention>
37
- `;
38
- }
39
-
40
- return looseFormatXml(instructions);
41
- };
42
-
43
- const formatContextObject = async (object: ReactiveEchoObject<any>): Promise<string> => {
44
- let data;
45
- try {
46
- data = await asyncTimeout(preprocessContextObject(object), CONTEXT_OBJECT_QUERY_TIMEOUT);
47
- } catch (err: any) {
48
- log.error('Failed to preprocess context object:', { err });
49
- data = object;
50
- }
51
-
52
- if (typeof data === 'string') {
53
- return data;
54
- } else {
55
- return `
56
- <object>
57
- <type>${getTypename(object)}</type>
58
- <id>${object.id}</id>
59
- ${formatObjectAsXMLTags(data)}
60
- </object>
61
- `;
62
- }
63
- };
64
-
65
- const preprocessContextObject = async (object: ReactiveEchoObject<any>): Promise<Record<string, any> | string> => {
66
- const space = getSpace(object);
67
- if (!space) {
68
- return { ...object };
69
- }
70
-
71
- // TODO(dmaretskyi): Serialize based on schema annotations.
72
- switch (getTypename(object)) {
73
- // TODO(dmaretskyi): Reference types somehow without plugin-automation depending on other plugins.
74
- case 'dxos.org/type/Document': {
75
- const data = space.db
76
- .query({ id: object.id }, { format: ResultFormat.Plain, include: { content: true } })
77
- .first() ?? { content: { content: '' } };
78
-
79
- return {
80
- ...data,
81
- threads: undefined,
82
- };
83
- }
84
-
85
- case 'dxos.org/type/Table': {
86
- // TODO(dmaretskyi): Load references.
87
- const schema = object.view ? space?.db.schemaRegistry.getSchema(object.view.query.typename) : undefined;
88
- const { objects: rows } =
89
- (schema &&
90
- (await space.db
91
- .query(Filter.schema(schema), { format: ResultFormat.Plain, limit: TABLE_ROWS_LIMIT })
92
- .run())) ??
93
- {};
94
-
95
- // TODO(dmaretskyi): Format table schema.
96
- return `
97
- <object>
98
- <id>${object.id}</id>
99
- <type>${getTypename(object)}</type>
100
- ${formatObjectAsXMLTags(object)}
101
-
102
- <rows>
103
- <!-- Limited to first ${TABLE_ROWS_LIMIT} rows. -->
104
- ${rows
105
- ?.map(
106
- (row: any) => `<row>
107
- ${formatObjectAsXMLTags(row)}
108
- </row>`,
109
- )
110
- .join('\n')}
111
- </rows>
112
-
113
- `;
114
- }
115
-
116
- default:
117
- return { ...object };
118
- }
119
- };
120
-
121
- const formatObjectAsXMLTags = (object: any, depth = 1): string => {
122
- return Object.entries(object)
123
- .filter(([key, value]) => ['string', 'number', 'boolean', 'object'].includes(typeof value))
124
- .map(([key, value]) => {
125
- if (typeof value === 'object' && value !== null) {
126
- if (depth === 0) {
127
- return '';
128
- } else {
129
- return `<${key}>
130
- ${formatObjectAsXMLTags(value, depth - 1)}
131
- </${key}>`;
132
- }
133
- }
134
-
135
- return `<${key}>${value}</${key}>`;
136
- })
137
- .join('\n');
138
- };
139
-
140
- const CONTEXT_OBJECT_QUERY_TIMEOUT = 5_000;
141
-
142
- const TABLE_ROWS_LIMIT = 10;
143
-
144
- /**
145
- * Formats XML indentation for instructions so they are easier to read during debugging.
146
- */
147
- const looseFormatXml = (xml: string): string => {
148
- let currentIndent = 0;
149
-
150
- return xml
151
- .split('\n')
152
- .map((line) => {
153
- if (line.match(RE_CLOSE_TAG_LINE)) {
154
- currentIndent--;
155
- }
156
- const indent = currentIndent;
157
- if (line.match(RE_OPEN_TAG_LINE)) {
158
- currentIndent++;
159
- }
160
- return ' '.repeat(indent * 2) + line.trimStart();
161
- })
162
- .join('\n');
163
- };
164
-
165
- const RE_OPEN_TAG_LINE = /^[ ]*<[a-zA-Z0-9\-_]+>[ ]*$/;
166
- const RE_CLOSE_TAG_LINE = /^[ ]*<\/[a-zA-Z0-9\-_]+>[ ]*$/;
@@ -1,57 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import '@dxos-theme';
6
-
7
- import { type Meta } from '@storybook/react';
8
- import React from 'react';
9
-
10
- import { FunctionTrigger } from '@dxos/functions';
11
- import { FunctionType } from '@dxos/plugin-script/types';
12
- import { create, useSpaces } from '@dxos/react-client/echo';
13
- import { withClientProvider } from '@dxos/react-client/testing';
14
- import { withLayout, withTheme } from '@dxos/storybook-utils';
15
-
16
- import { AutomationPanel } from './AutomationPanel';
17
- import { functions } from '../../testing';
18
- import translations from '../../translations';
19
- import { ChainPromptType } from '../../types';
20
-
21
- const DefaultStory = () => {
22
- const spaces = useSpaces();
23
- const space = spaces[1];
24
-
25
- return (
26
- <div role='none' className='flex w-[350px] border border-separator overflow-hidden'>
27
- <AutomationPanel space={space} />
28
- </div>
29
- );
30
- };
31
-
32
- const meta: Meta = {
33
- title: 'plugins/plugin-automation/AutomationPanel',
34
- component: AutomationPanel,
35
- render: DefaultStory,
36
- decorators: [
37
- withClientProvider({
38
- createIdentity: true,
39
- createSpace: true,
40
- types: [FunctionType, FunctionTrigger, ChainPromptType],
41
- onSpaceCreated: ({ space }) => {
42
- for (const fn of functions) {
43
- space.db.add(create(FunctionType, fn));
44
- }
45
- },
46
- }),
47
- withLayout({ fullscreen: true, tooltips: true, classNames: 'flex justify-center m-2' }),
48
- withTheme,
49
- ],
50
- parameters: {
51
- translations,
52
- },
53
- };
54
-
55
- export default meta;
56
-
57
- export const Default = {};
@@ -1,96 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import React, { useState } from 'react';
6
-
7
- import { type ReactiveObject, S } from '@dxos/echo-schema';
8
- import { FunctionTriggerSchema, FunctionTrigger, type FunctionTriggerType } from '@dxos/functions';
9
- import { create, Filter, useQuery, type Space } from '@dxos/react-client/echo';
10
- import { IconButton, Input, useTranslation } from '@dxos/react-ui';
11
- import { List } from '@dxos/react-ui-list';
12
- import { ghostHover, mx } from '@dxos/react-ui-theme';
13
-
14
- import { AUTOMATION_PLUGIN } from '../../meta';
15
- import { TriggerEditor, type TriggerEditorProps } from '../TriggerEditor';
16
-
17
- const grid = 'grid grid-cols-[40px_1fr_32px] min-bs-[2.5rem]';
18
-
19
- export type AutomationPanelProps = {
20
- space: Space;
21
- object?: ReactiveObject<any>;
22
- };
23
-
24
- // TODO(burdon): Factor out common layout with ViewEditor.
25
- export const AutomationPanel = ({ space }: AutomationPanelProps) => {
26
- const { t } = useTranslation(AUTOMATION_PLUGIN);
27
- const triggers = useQuery(space, Filter.schema(FunctionTrigger));
28
- const [trigger, setTrigger] = useState<FunctionTriggerType>();
29
- const [selected, setSelected] = useState<FunctionTrigger>();
30
-
31
- const handleSelect = (trigger: FunctionTrigger) => {
32
- const { id: _, ...values } = trigger;
33
- setTrigger(values);
34
- setSelected(trigger);
35
- };
36
-
37
- const handleAdd = () => {
38
- setTrigger(create(FunctionTriggerSchema, {}));
39
- setSelected(undefined);
40
- };
41
-
42
- const handleDelete = (trigger: FunctionTrigger) => {
43
- space.db.remove(trigger);
44
- setTrigger(undefined);
45
- setSelected(undefined);
46
- };
47
-
48
- const handleSave: TriggerEditorProps['onSave'] = (trigger) => {
49
- if (selected) {
50
- Object.assign(selected, trigger);
51
- } else {
52
- space.db.add(create(FunctionTrigger, trigger));
53
- }
54
-
55
- setTrigger(undefined);
56
- setSelected(undefined);
57
- };
58
-
59
- const handleCancel: TriggerEditorProps['onCancel'] = () => {
60
- setTrigger(undefined);
61
- };
62
-
63
- return (
64
- <div className='flex flex-col w-full divide-y divide-separator overflow-y-auto'>
65
- <List.Root<FunctionTrigger> items={triggers} isItem={S.is(FunctionTrigger)} getId={(field) => field.id}>
66
- {({ items: triggers }) => (
67
- <div role='list' className='flex flex-col w-full'>
68
- {triggers?.map((trigger) => (
69
- <List.Item<FunctionTrigger>
70
- key={trigger.id}
71
- item={trigger}
72
- classNames={mx(grid, ghostHover, 'items-center')}
73
- >
74
- <Input.Root>
75
- <Input.Switch checked={trigger.enabled} onCheckedChange={(checked) => (trigger.enabled = checked)} />
76
- </Input.Root>
77
- <List.ItemTitle classNames='px-2 cursor-pointer' onClick={() => handleSelect(trigger)}>
78
- {trigger.function}
79
- </List.ItemTitle>
80
- <List.ItemDeleteButton onClick={() => handleDelete(trigger)} />
81
- </List.Item>
82
- ))}
83
- </div>
84
- )}
85
- </List.Root>
86
-
87
- {trigger && <TriggerEditor space={space} trigger={trigger} onSave={handleSave} onCancel={handleCancel} />}
88
-
89
- {!trigger && (
90
- <div className='flex p-2 justify-center'>
91
- <IconButton icon='ph--plus--regular' label={t('new trigger')} onClick={handleAdd} />
92
- </div>
93
- )}
94
- </div>
95
- );
96
- };
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { AutomationPanel } from './AutomationPanel';
6
-
7
- export default AutomationPanel;
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- export * from './testing';
@@ -1,34 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { AST, S, toJsonSchema } from '@dxos/echo-schema';
6
-
7
- export const functions = [
8
- {
9
- name: 'example.com/function/chess',
10
- version: 1,
11
- inputSchema: toJsonSchema(
12
- S.Struct({
13
- level: S.Number.annotations({
14
- [AST.TitleAnnotationId]: 'Level',
15
- }),
16
- }),
17
- ),
18
- },
19
- {
20
- name: 'example.com/function/forex',
21
- version: 1,
22
- binding: 'FOREX',
23
- inputSchema: toJsonSchema(
24
- S.Struct({
25
- from: S.String.annotations({
26
- [AST.TitleAnnotationId]: 'Currency from',
27
- }),
28
- to: S.String.annotations({
29
- [AST.TitleAnnotationId]: 'Currency to',
30
- }),
31
- }),
32
- ),
33
- },
34
- ];