@dxos/react-ui-canvas-compute 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0

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 (75) hide show
  1. package/dist/lib/browser/index.mjs +894 -1059
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +894 -1059
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/compute.stories.d.ts +22 -1
  8. package/dist/types/src/compute.stories.d.ts.map +1 -1
  9. package/dist/types/src/graph/controller.d.ts +8 -4
  10. package/dist/types/src/graph/controller.d.ts.map +1 -1
  11. package/dist/types/src/hooks/useComputeNodeState.d.ts.map +1 -1
  12. package/dist/types/src/hooks/useGraphMonitor.d.ts +2 -2
  13. package/dist/types/src/hooks/useGraphMonitor.d.ts.map +1 -1
  14. package/dist/types/src/shapes/Audio.d.ts.map +1 -1
  15. package/dist/types/src/shapes/Beacon.d.ts.map +1 -1
  16. package/dist/types/src/shapes/Chat.d.ts.map +1 -1
  17. package/dist/types/src/shapes/Constant.d.ts.map +1 -1
  18. package/dist/types/src/shapes/{Queue.d.ts → Feed.d.ts} +8 -8
  19. package/dist/types/src/shapes/Feed.d.ts.map +1 -0
  20. package/dist/types/src/shapes/Function.d.ts.map +1 -1
  21. package/dist/types/src/shapes/Gpt.d.ts.map +1 -1
  22. package/dist/types/src/shapes/Json.d.ts.map +1 -1
  23. package/dist/types/src/shapes/RNG.d.ts.map +1 -1
  24. package/dist/types/src/shapes/Scope.d.ts.map +1 -1
  25. package/dist/types/src/shapes/Surface.d.ts.map +1 -1
  26. package/dist/types/src/shapes/Switch.d.ts.map +1 -1
  27. package/dist/types/src/shapes/Template.d.ts.map +1 -1
  28. package/dist/types/src/shapes/Text.d.ts.map +1 -1
  29. package/dist/types/src/shapes/Thread.d.ts.map +1 -1
  30. package/dist/types/src/shapes/Trigger.d.ts +4 -2
  31. package/dist/types/src/shapes/Trigger.d.ts.map +1 -1
  32. package/dist/types/src/shapes/common/Box.d.ts +4 -4
  33. package/dist/types/src/shapes/common/Box.d.ts.map +1 -1
  34. package/dist/types/src/shapes/common/FunctionBody.d.ts +2 -2
  35. package/dist/types/src/shapes/common/FunctionBody.d.ts.map +1 -1
  36. package/dist/types/src/shapes/index.d.ts +2 -2
  37. package/dist/types/src/shapes/index.d.ts.map +1 -1
  38. package/dist/types/src/testing/circuits.d.ts +18 -24
  39. package/dist/types/src/testing/circuits.d.ts.map +1 -1
  40. package/dist/types/tsconfig.tsbuildinfo +1 -1
  41. package/package.json +60 -56
  42. package/src/README.md +0 -3
  43. package/src/compute.stories.tsx +80 -116
  44. package/src/graph/controller.ts +101 -68
  45. package/src/graph/node-defs.ts +31 -31
  46. package/src/hooks/useComputeNodeState.ts +0 -1
  47. package/src/hooks/useGraphMonitor.ts +11 -10
  48. package/src/json.test.ts +3 -3
  49. package/src/registry.ts +2 -2
  50. package/src/schema.test.ts +11 -11
  51. package/src/shapes/Audio.tsx +2 -3
  52. package/src/shapes/Beacon.tsx +1 -2
  53. package/src/shapes/Boolean.tsx +2 -2
  54. package/src/shapes/Chat.tsx +0 -1
  55. package/src/shapes/Constant.tsx +0 -1
  56. package/src/shapes/{Queue.tsx → Feed.tsx} +26 -21
  57. package/src/shapes/Function.tsx +10 -8
  58. package/src/shapes/Gpt.tsx +6 -2
  59. package/src/shapes/GptRealtime.tsx +1 -1
  60. package/src/shapes/Json.tsx +7 -3
  61. package/src/shapes/RNG.tsx +0 -1
  62. package/src/shapes/Scope.tsx +1 -2
  63. package/src/shapes/Surface.tsx +4 -3
  64. package/src/shapes/Switch.tsx +1 -2
  65. package/src/shapes/Template.tsx +0 -1
  66. package/src/shapes/Text.tsx +0 -1
  67. package/src/shapes/Thread.tsx +15 -9
  68. package/src/shapes/Trigger.tsx +13 -8
  69. package/src/shapes/common/Box.tsx +8 -11
  70. package/src/shapes/common/FunctionBody.tsx +4 -4
  71. package/src/shapes/common/TypeSelect.tsx +1 -1
  72. package/src/shapes/defs.ts +3 -3
  73. package/src/shapes/index.ts +2 -2
  74. package/src/testing/circuits.ts +7 -16
  75. package/dist/types/src/shapes/Queue.d.ts.map +0 -1
@@ -6,8 +6,11 @@ import type * as Context from 'effect/Context';
6
6
  import * as Effect from 'effect/Effect';
7
7
  import * as Either from 'effect/Either';
8
8
  import * as Exit from 'effect/Exit';
9
+ import * as Layer from 'effect/Layer';
10
+ import type * as ManagedRuntime from 'effect/ManagedRuntime';
9
11
  import * as Scope from 'effect/Scope';
10
12
 
13
+ import type { AiService } from '@dxos/ai';
11
14
  import { Event, synchronized } from '@dxos/async';
12
15
  import {
13
16
  type ComputeEdge,
@@ -22,15 +25,23 @@ import {
22
25
  isNotExecuted,
23
26
  } from '@dxos/conductor';
24
27
  import { Resource } from '@dxos/context';
25
- import { type ComputeEventLogger, type ComputeEventPayload } from '@dxos/functions';
26
- import { type ServiceContainer } from '@dxos/functions-runtime';
28
+ import type { Database, Feed } from '@dxos/echo';
29
+ import { unwrapExit } from '@dxos/effect';
30
+ import {
31
+ ComputeEventLogger,
32
+ type ComputeEventPayload,
33
+ type CredentialsService,
34
+ type FunctionInvocationService,
35
+ type QueueService,
36
+ Trace,
37
+ TracingService,
38
+ } from '@dxos/functions';
27
39
  import { log } from '@dxos/log';
28
40
  import { type CanvasGraphModel } from '@dxos/react-ui-canvas-editor';
29
41
  import { type ContentBlock } from '@dxos/types';
30
42
 
31
43
  import { createComputeGraph } from '../hooks';
32
44
  import { type ComputeShape } from '../shapes';
33
-
34
45
  import { resolveComputeNode } from './node-defs';
35
46
 
36
47
  // TODO(burdon): API package for conductor.
@@ -72,6 +83,15 @@ type ComputeOutputEvent = {
72
83
  value: RuntimeValue;
73
84
  };
74
85
 
86
+ // TODO(dmaretskyi): Re-use function servies definition.
87
+ export type ComputeServices =
88
+ | AiService.AiService
89
+ | Database.Service
90
+ | Feed.FeedService
91
+ | QueueService
92
+ | CredentialsService
93
+ | FunctionInvocationService;
94
+
75
95
  /**
76
96
  * Nodes that will automatically trigger the execution of the graph on startup.
77
97
  */
@@ -79,10 +99,10 @@ const AUTO_TRIGGER_NODES = ['chat', 'switch', 'constant'];
79
99
 
80
100
  export const createComputeGraphController = (
81
101
  graph: CanvasGraphModel<ComputeShape>,
82
- serviceContainer: ServiceContainer,
102
+ computeRuntime: ManagedRuntime.ManagedRuntime<ComputeServices, never>,
83
103
  ) => {
84
104
  const computeGraph = createComputeGraph(graph);
85
- const controller = new ComputeGraphController(serviceContainer, computeGraph);
105
+ const controller = new ComputeGraphController(computeRuntime, computeGraph);
86
106
  return { controller, graph };
87
107
  };
88
108
 
@@ -117,7 +137,7 @@ export class ComputeGraphController extends Resource {
117
137
  public readonly events = new Event<ComputeEventPayload>();
118
138
 
119
139
  constructor(
120
- private readonly _serviceContainer: ServiceContainer,
140
+ private readonly _computeRuntime: ManagedRuntime.ManagedRuntime<ComputeServices, never>,
121
141
  /** Persistent compute graph. */
122
142
  private readonly _graph: ComputeGraphModel,
123
143
  ) {
@@ -232,37 +252,42 @@ export class ComputeGraphController extends Resource {
232
252
  executor.setOutputs(nodeId, Effect.succeed(ValueBag.make(outputs)));
233
253
  }
234
254
 
235
- const serviceLayer = this._serviceContainer.createLayer();
236
- await Effect.runPromise(
237
- Effect.gen(this, function* () {
238
- const scope = yield* Scope.make();
239
-
240
- // TODO(dmaretskyi): Code duplication.
241
- const executable = yield* Effect.promise(() => resolveComputeNode(this._graph.getNode(nodeId)));
242
- const computingOutputs = executable.exec != null;
243
- // TODO(dmaretskyi): Check if the node has a compute function and run computeOutputs if it does.
244
- const effect = (computingOutputs ? executor.computeOutputs(nodeId) : executor.computeInputs(nodeId)).pipe(
245
- Effect.withSpan('runGraph'),
246
- Scope.extend(scope),
247
-
248
- Effect.flatMap(computeValueBag),
249
- Effect.provide(serviceLayer),
250
- Effect.withSpan('test'),
251
- Effect.tap((values) => {
252
- for (const [key, value] of Object.entries(values)) {
253
- if (computingOutputs) {
254
- this._onOutputComputed(nodeId, key, value);
255
- } else {
256
- this._onInputComputed(nodeId, key, value);
255
+ unwrapExit(
256
+ await this._computeRuntime.runPromiseExit(
257
+ Effect.gen(this, function* () {
258
+ const scope = yield* Scope.make();
259
+
260
+ // TODO(dmaretskyi): Code duplication.
261
+ const executable = yield* Effect.promise(() => resolveComputeNode(this._graph.getNode(nodeId)));
262
+ const computingOutputs = executable.exec != null;
263
+ // TODO(dmaretskyi): Check if the node has a compute function and run computeOutputs if it does.
264
+ const effect = (computingOutputs ? executor.computeOutputs(nodeId) : executor.computeInputs(nodeId)).pipe(
265
+ Effect.withSpan('runGraph'),
266
+ Scope.extend(scope),
267
+ Effect.provide(
268
+ ComputeEventLogger.layerFromTracing.pipe(
269
+ Layer.provideMerge(TracingService.layerNoop), // TODO(dmaretskyi): Plug-in tracing events to visual feedback in the compute graph editor.
270
+ Layer.provideMerge(Trace.writerLayerNoop),
271
+ ),
272
+ ),
273
+ Effect.flatMap(computeValueBag),
274
+ Effect.withSpan('test'),
275
+ Effect.tap((values) => {
276
+ for (const [key, value] of Object.entries(values)) {
277
+ if (computingOutputs) {
278
+ this._onOutputComputed(nodeId, key, value);
279
+ } else {
280
+ this._onInputComputed(nodeId, key, value);
281
+ }
257
282
  }
258
- }
259
- }),
260
- );
283
+ }),
284
+ );
261
285
 
262
- yield* effect;
286
+ yield* effect;
263
287
 
264
- yield* Scope.close(scope, Exit.void);
265
- }),
288
+ yield* Scope.close(scope, Exit.void);
289
+ }),
290
+ ),
266
291
  );
267
292
 
268
293
  this.update.emit();
@@ -290,44 +315,52 @@ export class ComputeGraphController extends Resource {
290
315
  : this._graph.nodes.filter((node) => node.type != null && AUTO_TRIGGER_NODES.includes(node.type));
291
316
  const allAffectedNodes = [...new Set(triggerNodes.flatMap((node) => executor.getAllDependantNodes(node.id)))];
292
317
 
293
- await Effect.runPromise(
294
- Effect.gen(this, function* () {
295
- const scope = yield* Scope.make();
296
-
297
- // TODO(burdon): Return map?
298
- const tasks: Effect.Effect<unknown, any, never>[] = [];
299
- for (const node of allAffectedNodes) {
300
- // TODO(dmaretskyi): Code duplication.
301
- const executable = yield* Effect.promise(() => resolveComputeNode(this._graph.getNode(node)));
302
- const computingOutputs = executable.exec != null;
303
-
304
- // TODO(dmaretskyi): Check if the node has a compute function and run computeOutputs if it does.
305
- const effect = (computingOutputs ? executor.computeOutputs(node) : executor.computeInputs(node)).pipe(
306
- Effect.withSpan('runGraph'),
307
- Scope.extend(scope),
308
- Effect.flatMap(computeValueBag),
309
- Effect.provide(this._serviceContainer.createLayer()),
310
- Effect.withSpan('test'),
311
- Effect.tap((values) => {
312
- for (const [key, value] of Object.entries(values)) {
313
- if (computingOutputs) {
314
- this._onOutputComputed(node, key, value);
315
- } else {
316
- this._onInputComputed(node, key, value);
318
+ unwrapExit(
319
+ await this._computeRuntime.runPromiseExit(
320
+ Effect.gen(this, function* () {
321
+ const scope = yield* Scope.make();
322
+
323
+ // TODO(burdon): Return map?
324
+ const tasks: Effect.Effect<unknown, any, ComputeServices>[] = [];
325
+ for (const node of allAffectedNodes) {
326
+ // TODO(dmaretskyi): Code duplication.
327
+ const executable = yield* Effect.promise(() => resolveComputeNode(this._graph.getNode(node)));
328
+ const computingOutputs = executable.exec != null;
329
+
330
+ // TODO(dmaretskyi): Check if the node has a compute function and run computeOutputs if it does.
331
+ const effect = (computingOutputs ? executor.computeOutputs(node) : executor.computeInputs(node)).pipe(
332
+ Effect.withSpan('runGraph'),
333
+ Scope.extend(scope),
334
+ Effect.flatMap(computeValueBag),
335
+ Effect.provide(
336
+ ComputeEventLogger.layerFromTracing.pipe(
337
+ Layer.provideMerge(TracingService.layerNoop), // TODO(dmaretskyi): Plug-in tracing events to visual feedback in the compute graph editor.
338
+ Layer.provideMerge(Trace.writerLayerNoop),
339
+ ),
340
+ ),
341
+
342
+ Effect.withSpan('test'),
343
+ Effect.tap((values) => {
344
+ for (const [key, value] of Object.entries(values)) {
345
+ if (computingOutputs) {
346
+ this._onOutputComputed(node, key, value);
347
+ } else {
348
+ this._onInputComputed(node, key, value);
349
+ }
317
350
  }
318
- }
319
- }),
320
- );
351
+ }),
352
+ );
321
353
 
322
- tasks.push(effect);
323
- }
354
+ tasks.push(effect);
355
+ }
324
356
 
325
- //
326
- yield* Effect.all(tasks);
357
+ //
358
+ yield* Effect.all(tasks);
327
359
 
328
- //
329
- yield* Scope.close(scope, Exit.void);
330
- }),
360
+ //
361
+ yield* Scope.close(scope, Exit.void);
362
+ }),
363
+ ),
331
364
  );
332
365
 
333
366
  this.update.emit();
@@ -12,7 +12,7 @@ import {
12
12
  registry,
13
13
  } from '@dxos/conductor';
14
14
  import { raise } from '@dxos/debug';
15
- import { ObjectId, toJsonSchema } from '@dxos/echo/internal';
15
+ import { JsonSchema, Obj } from '@dxos/echo';
16
16
  import { invariant } from '@dxos/invariant';
17
17
 
18
18
  import { type ComputeShape, type ConstantShape, type TemplateShape } from '../shapes';
@@ -39,45 +39,45 @@ const nodeFactory: Record<NodeType | 'trigger', (shape: ComputeShape) => Compute
39
39
  [NODE_OUTPUT]: () => createNode(NODE_OUTPUT),
40
40
 
41
41
  // Extensions.
42
- ['text-to-image' as const]: () => createNode('text-to-image'), // TODO(burdon): Rename ai-impage-tool
43
- ['and' as const]: () => createNode('and'),
44
- ['append' as const]: () => createNode('append'),
45
- ['audio' as const]: () => createNode('audio'),
46
- ['beacon' as const]: () => createNode('beacon'),
47
- ['chat' as const]: () => createNode('chat'),
48
- ['constant' as const]: (shape) =>
42
+ 'text-to-image': () => createNode('text-to-image'), // TODO(burdon): Rename ai-impage-tool
43
+ and: () => createNode('and'),
44
+ append: () => createNode('append'),
45
+ audio: () => createNode('audio'),
46
+ beacon: () => createNode('beacon'),
47
+ chat: () => createNode('chat'),
48
+ constant: (shape) =>
49
49
  createNode('constant', {
50
50
  value: (shape as ConstantShape).value,
51
51
  }),
52
- ['make-queue' as const]: () => createNode('make-queue'),
53
- ['database' as const]: () => createNode('database'),
54
- ['gpt' as const]: () => createNode('gpt'),
55
- ['gpt-realtime' as const]: () => createNode('gpt-realtime'),
56
- ['if' as const]: () => createNode('if'),
57
- ['if-else' as const]: () => createNode('if-else'),
58
- ['function' as const]: () => createNode('function'),
59
- ['json' as const]: () => createNode('json'),
60
- ['json-transform' as const]: () => createNode('json-transform'),
61
- ['not' as const]: () => createNode('not'),
62
- ['or' as const]: () => createNode('or'),
63
- ['queue' as const]: () => createNode('queue'),
64
- ['rng' as const]: () => createNode('rng'),
65
- ['reducer' as const]: () => createNode('reducer'),
66
- ['scope' as const]: () => createNode('scope'),
67
- ['surface' as const]: () => createNode('surface'),
68
- ['switch' as const]: () => createNode('switch'),
69
- ['template' as const]: (shape) => {
52
+ 'make-queue': () => createNode('make-queue'),
53
+ database: () => createNode('database'),
54
+ gpt: () => createNode('gpt'),
55
+ 'gpt-realtime': () => createNode('gpt-realtime'),
56
+ if: () => createNode('if'),
57
+ 'if-else': () => createNode('if-else'),
58
+ function: () => createNode('function'),
59
+ json: () => createNode('json'),
60
+ 'json-transform': () => createNode('json-transform'),
61
+ not: () => createNode('not'),
62
+ or: () => createNode('or'),
63
+ queue: () => createNode('queue'),
64
+ rng: () => createNode('rng'),
65
+ reducer: () => createNode('reducer'),
66
+ scope: () => createNode('scope'),
67
+ surface: () => createNode('surface'),
68
+ switch: () => createNode('switch'),
69
+ template: (shape) => {
70
70
  const node = createNode('template', { valueType: (shape as TemplateShape).valueType, value: shape.text });
71
- node.inputSchema = toJsonSchema(getTemplateInputSchema(node));
71
+ node.inputSchema = JsonSchema.toJsonSchema(getTemplateInputSchema(node));
72
72
  return node;
73
73
  },
74
- ['text' as const]: () => createNode('text'),
75
- ['thread' as const]: () => createNode('thread'),
76
- ['trigger' as const]: () => createNode(NODE_INPUT),
74
+ text: () => createNode('text'),
75
+ thread: () => createNode('thread'),
76
+ trigger: () => createNode(NODE_INPUT),
77
77
  };
78
78
 
79
79
  const createNode = (type: string, props?: Partial<ComputeNode>): ComputeNode => ({
80
- id: ObjectId.random(),
80
+ id: Obj.ID.random(),
81
81
  type,
82
82
  ...props,
83
83
  });
@@ -11,7 +11,6 @@ import { invariant } from '@dxos/invariant';
11
11
 
12
12
  import { type RuntimeValue } from '../graph';
13
13
  import { type ComputeShape } from '../shapes';
14
-
15
14
  import { useComputeContext } from './compute-context';
16
15
 
17
16
  export type ComputeNodeState = {
@@ -5,10 +5,9 @@
5
5
  import { useMemo } from 'react';
6
6
 
7
7
  import { type ComputeEdge, ComputeGraphModel, type ComputeNode, DEFAULT_INPUT, DEFAULT_OUTPUT } from '@dxos/conductor';
8
- import { ObjectId, Ref } from '@dxos/echo/internal';
8
+ import { Obj, Ref } from '@dxos/echo';
9
9
  import { invariant } from '@dxos/invariant';
10
- import { getSpace } from '@dxos/react-client/echo';
11
- import { type CanvasGraphModel, type Connection, type GraphMonitor } from '@dxos/react-ui-canvas-editor';
10
+ import { type CanvasBoard, type CanvasGraphModel, type GraphMonitor } from '@dxos/react-ui-canvas-editor';
12
11
  import { isNonNullable } from '@dxos/util';
13
12
 
14
13
  import { createComputeNode, isValidComputeNode } from '../graph';
@@ -19,7 +18,7 @@ import { type ComputeShape, type TriggerShape } from '../shapes';
19
18
  */
20
19
  export const mapEdge = (
21
20
  graph: CanvasGraphModel,
22
- { source, target, output = DEFAULT_OUTPUT, input = DEFAULT_INPUT }: Connection,
21
+ { source, target, output = DEFAULT_OUTPUT, input = DEFAULT_INPUT }: CanvasBoard.Connection,
23
22
  ): ComputeEdge => {
24
23
  const sourceNode = graph.findNode(source) as ComputeShape;
25
24
  const targetNode = graph.findNode(target) as ComputeShape;
@@ -27,7 +26,7 @@ export const mapEdge = (
27
26
  invariant(targetNode?.node);
28
27
 
29
28
  return {
30
- id: ObjectId.random(),
29
+ id: Obj.ID.random(),
31
30
  source: sourceNode.node,
32
31
  target: targetNode.node,
33
32
  output,
@@ -113,19 +112,21 @@ export const createComputeGraph = (graph?: CanvasGraphModel<ComputeShape>) => {
113
112
  const linkTriggerToCompute = (graph: ComputeGraphModel, computeNode: ComputeNode, triggerData: TriggerShape) => {
114
113
  const functionTrigger = triggerData.functionTrigger?.target;
115
114
  invariant(functionTrigger);
116
- functionTrigger.function = Ref.make(graph.root);
117
- functionTrigger.inputNodeId = computeNode.id;
115
+ Obj.change(functionTrigger, (obj) => {
116
+ obj.function = Ref.make(graph.root);
117
+ obj.inputNodeId = computeNode.id;
118
+ });
118
119
  };
119
120
 
120
121
  const deleteTriggerObjects = (computeGraph: ComputeGraphModel, deleted: CanvasGraphModel) => {
121
- const space = getSpace(computeGraph.root);
122
- if (!space) {
122
+ const db = Obj.getDatabase(computeGraph.root);
123
+ if (!db) {
123
124
  return;
124
125
  }
125
126
  for (const node of deleted.nodes) {
126
127
  if (node.type === 'trigger') {
127
128
  const trigger = node as TriggerShape;
128
- space.db.remove(trigger.functionTrigger!.target!);
129
+ db.remove(trigger.functionTrigger!.target!);
129
130
  }
130
131
  }
131
132
  };
package/src/json.test.ts CHANGED
@@ -5,12 +5,12 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
- import { BaseGraphEdge, BaseGraphNode } from '@dxos/graph';
8
+ import { Graph } from '@dxos/graph';
9
9
 
10
10
  import { createGptCircuit } from './testing';
11
11
 
12
12
  export const Shape = Schema.extend(
13
- BaseGraphNode,
13
+ Graph.Node,
14
14
  Schema.Struct({
15
15
  text: Schema.optional(Schema.String),
16
16
  guide: Schema.optional(Schema.Boolean),
@@ -19,7 +19,7 @@ export const Shape = Schema.extend(
19
19
  );
20
20
 
21
21
  export const Connection = Schema.extend(
22
- BaseGraphEdge,
22
+ Graph.Edge,
23
23
  Schema.Struct({
24
24
  input: Schema.optional(Schema.String),
25
25
  output: Schema.optional(Schema.String),
package/src/registry.ts CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  jsonTransformShape,
23
23
  notShape,
24
24
  orShape,
25
- queueShape,
25
+ feedShape,
26
26
  randomShape,
27
27
  reducerShape,
28
28
  scopeShape,
@@ -82,7 +82,7 @@ export const computeShapes: { title: string; shapes: ShapeDef[] }[] = [
82
82
  shapes: [
83
83
  //
84
84
  jsonShape,
85
- queueShape,
85
+ feedShape,
86
86
  threadShape,
87
87
  textShape,
88
88
  surfaceShape,
@@ -5,11 +5,11 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
- import { live } from '@dxos/echo/internal';
9
- import { BaseGraphNode, Graph } from '@dxos/graph';
8
+ import { Graph } from '@dxos/graph';
10
9
  import {
10
+ CanvasBoard,
11
+ CanvasGraphModel,
11
12
  Polygon,
12
- Shape,
13
13
  createEllipse,
14
14
  createPath,
15
15
  createRectangle,
@@ -21,25 +21,25 @@ import { ComputeShape, createFunction, createSwitch } from './shapes';
21
21
 
22
22
  describe('compute', () => {
23
23
  test('model', ({ expect }) => {
24
- // const model = CanvasGraphModel.create<ComputeShape>();
24
+ const model = CanvasGraphModel.create<ComputeShape>();
25
25
  const node = createSwitch({ id: 'x', center: { x: 0, y: 0 }, size: { width: 80, height: 80 } });
26
26
  console.log(JSON.stringify(node, null, 2));
27
27
  expect(Schema.is(ComputeShape)(node)).toBe(true);
28
28
  expect(Schema.is(Polygon)(node)).toBe(true);
29
- expect(Schema.is(Shape)(node)).toBe(true);
30
- expect(Schema.is(BaseGraphNode)(node)).toBe(true);
29
+ expect(Schema.is(CanvasBoard.Shape)(node)).toBe(true);
30
+ expect(Schema.is(Graph.Node)(node)).toBe(true);
31
31
 
32
- const graph = live(Graph, { nodes: [], edges: [] });
33
- graph.nodes.push(node); // Throws.
32
+ const graph: Graph.Any = { nodes: [], edges: [] };
33
+ graph.nodes.push(node);
34
34
 
35
- // model.createNode(node);
36
- // console.log(JSON.stringify(model, null, 2));
35
+ model.createNode(node);
36
+ console.log(JSON.stringify(model, null, 2));
37
37
  });
38
38
  });
39
39
 
40
40
  describe('schema', () => {
41
41
  test('basic types', ({ expect }) => {
42
- const shapes: Shape[] = [];
42
+ const shapes: CanvasBoard.Shape[] = [];
43
43
  shapes.push(createRectangle({ id: 'shape-1', center: { x: 0, y: 0 }, size: { width: 80, height: 80 } }));
44
44
  shapes.push(createEllipse({ id: 'shape-2', center: { x: 0, y: 0 }, size: { width: 80, height: 80 } }));
45
45
  shapes.push(createFunction({ id: 'shape-3', center: { x: 0, y: 0 } }));
@@ -9,7 +9,6 @@ import { Icon } from '@dxos/react-ui';
9
9
  import { type ShapeComponentProps, type ShapeDef, createAnchorMap } from '@dxos/react-ui-canvas-editor';
10
10
 
11
11
  import { useComputeNodeState } from '../hooks';
12
-
13
12
  import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs';
14
13
 
15
14
  export const AudioShape = Schema.extend(
@@ -35,10 +34,10 @@ export const AudioComponent = ({ shape }: ShapeComponentProps<AudioShape>) => {
35
34
 
36
35
  // https://docs.pmnd.rs/react-three-fiber/api/canvas#render-props
37
36
  return (
38
- <div className='flex is-full justify-center items-center'>
37
+ <div className='flex w-full justify-center items-center'>
39
38
  <Icon
40
39
  icon={active ? 'ph--microphone--regular' : 'ph--microphone-slash--regular'}
41
- classNames={['transition opacity-20 duration-1000', active && 'opacity-100 text-red-500']}
40
+ classNames={['transition opacity-20 duration-1000', active && 'opacity-100 text-error-text']}
42
41
  size={8}
43
42
  onClick={() => setActive(!active)}
44
43
  />
@@ -10,7 +10,6 @@ import { Icon } from '@dxos/react-ui';
10
10
  import { type ShapeComponentProps, type ShapeDef, createAnchorMap } from '@dxos/react-ui-canvas-editor';
11
11
 
12
12
  import { useComputeNodeState } from '../hooks';
13
-
14
13
  import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs';
15
14
 
16
15
  export const BeaconShape = Schema.extend(
@@ -33,7 +32,7 @@ export const BeaconComponent = ({ shape }: ShapeComponentProps<BeaconShape>) =>
33
32
  const value = input?.type === 'executed' ? input.value : false;
34
33
 
35
34
  return (
36
- <div className='flex is-full justify-center items-center'>
35
+ <div className='flex w-full justify-center items-center'>
37
36
  <Icon
38
37
  icon='ph--sun--regular'
39
38
  classNames={['transition opacity-20 duration-1000', isTruthy(value) && 'opacity-100 text-yellow-500']}
@@ -57,7 +57,7 @@ const defineShape = <S extends GateShape>({
57
57
  // Be careful not to name component factories with a capital letter.
58
58
  component: () => {
59
59
  return (
60
- <div className='flex is-full justify-center items-center'>
60
+ <div className='flex w-full justify-center items-center'>
61
61
  <Symbol />
62
62
  </div>
63
63
  );
@@ -95,7 +95,7 @@ const createSymbol =
95
95
  const paths = pathConstructor({ startX, endX, height });
96
96
 
97
97
  return (
98
- <svg viewBox={`0 0 ${width} ${height}`} className='is-full bs-full'>
98
+ <svg viewBox={`0 0 ${width} ${height}`} className='h-full w-full'>
99
99
  {/* Input line. */}
100
100
  {getAnchorPoints({ x: 0, y: centerY }, inputs).map(({ x, y }, i) => (
101
101
  <line key={i} x1={x} y1={y} x2={startX * 1.3} y2={y} strokeWidth={strokeWidth} className={className} />
@@ -16,7 +16,6 @@ import {
16
16
  import { createAnchorMap } from '@dxos/react-ui-canvas-editor';
17
17
 
18
18
  import { useComputeNodeState } from '../hooks';
19
-
20
19
  import { Box } from './common';
21
20
  import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs';
22
21
 
@@ -18,7 +18,6 @@ import { createAnchorMap } from '@dxos/react-ui-canvas-editor';
18
18
  import { safeParseJson } from '@dxos/util';
19
19
 
20
20
  import { useComputeNodeState } from '../hooks';
21
-
22
21
  import { Box, TypeSelect } from './common';
23
22
  import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs';
24
23
 
@@ -6,31 +6,34 @@ import * as Schema from 'effect/Schema';
6
6
  import React, { Fragment } from 'react';
7
7
 
8
8
  import { DEFAULT_OUTPUT, QueueInput, QueueOutput } from '@dxos/conductor';
9
- import { type ThemedClassName } from '@dxos/react-ui';
9
+ import { ScrollArea, type ThemedClassName } from '@dxos/react-ui';
10
10
  import { type ShapeComponentProps, type ShapeDef } from '@dxos/react-ui-canvas-editor';
11
- import { mx } from '@dxos/react-ui-theme';
11
+ import { mx } from '@dxos/ui-theme';
12
12
 
13
13
  import { useComputeNodeState } from '../hooks';
14
-
15
14
  import { createFunctionAnchors } from './common';
16
15
  import { Box, type BoxActionHandler } from './common';
17
16
  import { ComputeShape, type CreateShapeProps, createShape } from './defs';
18
17
 
19
- export const QueueShape = Schema.extend(
18
+ export const FeedShape = Schema.extend(
20
19
  ComputeShape,
21
20
  Schema.Struct({
22
21
  type: Schema.Literal('queue'),
23
22
  }),
24
23
  );
25
24
 
26
- export type QueueShape = Schema.Schema.Type<typeof QueueShape>;
25
+ export type FeedShape = Schema.Schema.Type<typeof FeedShape>;
27
26
 
28
- export type CreateQueueProps = CreateShapeProps<QueueShape>;
27
+ export type CreateFeedProps = CreateShapeProps<FeedShape>;
29
28
 
30
- export const createQueue = (props: CreateQueueProps) =>
31
- createShape<QueueShape>({ type: 'queue', size: { width: 256, height: 512 }, ...props });
29
+ export const createFeed = (props: CreateFeedProps) =>
30
+ createShape<FeedShape>({
31
+ type: 'queue',
32
+ size: { width: 256, height: 512 },
33
+ ...props,
34
+ });
32
35
 
33
- export const QueueComponent = ({ shape }: ShapeComponentProps<QueueShape>) => {
36
+ export const FeedComponent = ({ shape }: ShapeComponentProps<FeedShape>) => {
34
37
  const { runtime } = useComputeNodeState(shape);
35
38
  const items = runtime.outputs[DEFAULT_OUTPUT]?.type === 'executed' ? runtime.outputs[DEFAULT_OUTPUT].value : [];
36
39
 
@@ -42,22 +45,24 @@ export const QueueComponent = ({ shape }: ShapeComponentProps<QueueShape>) => {
42
45
 
43
46
  return (
44
47
  <Box shape={shape} status={`${items.length} items`} onAction={handleAction}>
45
- <div className='flex flex-col is-full overflow-y-auto divide-y divide-separator'>
46
- {[...items].map((item, i) => (
47
- <QueueItem key={i} classNames='p-1 pli-2' item={item} />
48
- ))}
49
- </div>
48
+ <ScrollArea.Root orientation='vertical'>
49
+ <ScrollArea.Viewport classNames='divide-y divide-separator'>
50
+ {[...items].map((item, i) => (
51
+ <FeedItem key={i} classNames='p-1 px-2' item={item} />
52
+ ))}
53
+ </ScrollArea.Viewport>
54
+ </ScrollArea.Root>
50
55
  </Box>
51
56
  );
52
57
  };
53
58
 
54
- export const QueueItem = ({ classNames, item }: ThemedClassName<{ item: any }>) => {
59
+ export const FeedItem = ({ classNames, item }: ThemedClassName<{ item: any }>) => {
55
60
  if (typeof item !== 'object') {
56
61
  return <div className={mx(classNames, 'whitespace-pre-wrap')}>{item}</div>;
57
62
  }
58
63
 
59
64
  return (
60
- <div className={mx('grid grid-cols-[80px,1fr]', classNames)}>
65
+ <div className={mx('grid grid-cols-[80px_1fr]', classNames)}>
61
66
  {Object.entries(item).map(([key, value]) => (
62
67
  <Fragment key={key}>
63
68
  <div className='p-1 text-xs text-subdued'>{key}</div>
@@ -68,12 +73,12 @@ export const QueueItem = ({ classNames, item }: ThemedClassName<{ item: any }>)
68
73
  );
69
74
  };
70
75
 
71
- export const queueShape: ShapeDef<QueueShape> = {
72
- type: 'queue',
73
- name: 'Queue',
76
+ export const feedShape: ShapeDef<FeedShape> = {
77
+ type: 'feed',
78
+ name: 'Feed',
74
79
  icon: 'ph--queue--regular',
75
- component: QueueComponent,
76
- createShape: createQueue,
80
+ component: FeedComponent,
81
+ createShape: createFeed,
77
82
  getAnchors: (shape) => createFunctionAnchors(shape, QueueInput, QueueOutput),
78
83
  resizable: true,
79
84
  };