@dxos/app-graph 0.8.4-main.f9ba587 → 0.8.4-main.fffef41

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.
@@ -2,40 +2,39 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { type Registry, RegistryContext, Rx, useRxValue } from '@effect-rx/rx-react';
8
- import { Pause, Play, Plus, Timer } from '@phosphor-icons/react';
9
- import { type Meta } from '@storybook/react-vite';
10
- import { Option, pipe } from 'effect';
5
+ import { Atom, type Registry, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
6
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
7
+ import * as Function from 'effect/Function';
8
+ import * as Option from 'effect/Option';
11
9
  import React, { type PropsWithChildren, useCallback, useContext, useEffect, useMemo, useState } from 'react';
12
10
 
13
11
  import {
14
- live,
15
- isSpace,
12
+ Expando,
13
+ Filter,
14
+ type Live,
16
15
  Query,
17
16
  type QueryResult,
18
17
  type Space,
19
18
  SpaceState,
20
- Expando,
21
- type Live,
22
- Filter,
19
+ isSpace,
20
+ live,
23
21
  } from '@dxos/client/echo';
24
22
  import { Obj, Type } from '@dxos/echo';
25
23
  import { faker } from '@dxos/random';
26
24
  import { type Client, useClient } from '@dxos/react-client';
27
25
  import { withClientProvider } from '@dxos/react-client/testing';
28
- import { Button, Input, Select } from '@dxos/react-ui';
26
+ import { Icon, IconButton, Input, Select } from '@dxos/react-ui';
27
+ import { withTheme } from '@dxos/react-ui/testing';
29
28
  import { Path, Tree } from '@dxos/react-ui-list';
30
29
  import { getSize, mx } from '@dxos/react-ui-theme';
31
- import { withTheme } from '@dxos/storybook-utils';
32
30
  import { byPosition, isNonNullable, safeParseInt } from '@dxos/util';
33
31
 
34
- import { JsonTree } from './Tree';
35
32
  import { type ExpandableGraph, ROOT_ID } from '../graph';
36
- import { GraphBuilder, createExtension, rxFromObservable, rxFromSignal } from '../graph-builder';
33
+ import { GraphBuilder, atomFromObservable, createExtension } from '../graph-builder';
37
34
  import { type Node } from '../node';
38
- import { rxFromQuery } from '../testing';
35
+ import { atomFromQuery } from '../testing';
36
+
37
+ import { JsonTree } from './Tree';
39
38
 
40
39
  const DEFAULT_PERIOD = 500;
41
40
 
@@ -61,18 +60,20 @@ const createGraph = (client: Client, registry: Registry.Registry): ExpandableGra
61
60
  const spaceBuilderExtension = createExtension({
62
61
  id: 'space',
63
62
  connector: (node) =>
64
- Rx.make((get) =>
65
- pipe(
63
+ Atom.make((get) =>
64
+ Function.pipe(
66
65
  get(node),
67
66
  Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
68
67
  Option.map(() => {
69
- const spaces = get(rxFromObservable(client.spaces)) ?? [];
68
+ const spaces = get(atomFromObservable(client.spaces)) ?? [];
70
69
  return spaces
71
- .filter((space) => get(rxFromObservable(space.state)) === SpaceState.SPACE_READY)
70
+ .filter((space) => get(atomFromObservable(space.state)) === SpaceState.SPACE_READY)
72
71
  .map((space) => ({
73
72
  id: space.id,
74
73
  type: 'dxos.org/type/Space',
75
- properties: { label: get(rxFromSignal(() => space.properties.name)) },
74
+ properties: {
75
+ label: get(atomFromObservable(space.properties.name)),
76
+ },
76
77
  data: space,
77
78
  }));
78
79
  }),
@@ -85,15 +86,15 @@ const createGraph = (client: Client, registry: Registry.Registry): ExpandableGra
85
86
  id: 'object',
86
87
  connector: (node) => {
87
88
  let query: QueryResult<Live<Expando>> | undefined;
88
- return Rx.make((get) =>
89
- pipe(
89
+ return Atom.make((get) =>
90
+ Function.pipe(
90
91
  get(node),
91
92
  Option.flatMap((node) => (isSpace(node.data) ? Option.some(node.data) : Option.none())),
92
93
  Option.map((space) => {
93
94
  if (!query) {
94
95
  query = space.db.query(Query.type(Expando, { type: 'test' }));
95
96
  }
96
- const objects = get(rxFromQuery(query));
97
+ const objects = get(atomFromQuery(query));
97
98
  return objects.map((object) => ({
98
99
  id: object.id,
99
100
  type: 'dxos.org/type/test',
@@ -160,7 +161,12 @@ const runAction = async (client: Client, action: Action) => {
160
161
  }
161
162
 
162
163
  case Action.ADD_OBJECT:
163
- getRandomSpace(client)?.db.add(Obj.make(Type.Expando, { type: 'test', name: faker.commerce.productName() }));
164
+ getRandomSpace(client)?.db.add(
165
+ Obj.make(Type.Expando, {
166
+ type: 'test',
167
+ name: faker.commerce.productName(),
168
+ }),
169
+ );
164
170
  break;
165
171
 
166
172
  case Action.REMOVE_OBJECT: {
@@ -205,23 +211,25 @@ const Controls = ({ children }: PropsWithChildren) => {
205
211
  return (
206
212
  <>
207
213
  <div className='flex shrink-0 p-2 space-x-2'>
208
- <Button onClick={() => setGenerating((generating) => !generating)}>{generating ? <Pause /> : <Play />}</Button>
214
+ <IconButton
215
+ icon={generating ? 'ph--pause--regular' : 'ph--play--regular'}
216
+ label={generating ? 'Pause' : 'Play'}
217
+ onClick={() => setGenerating((generating) => !generating)}
218
+ />
209
219
  <div className='relative' title='mutation period'>
210
220
  <Input.Root>
211
221
  <Input.TextInput
212
222
  autoComplete='off'
213
223
  size={5}
214
- classNames='w-[100px] text-right pie-[22px]'
224
+ classNames='is-[100px] text-right pie-[22px]'
215
225
  placeholder='Interval'
216
226
  value={actionInterval}
217
227
  onChange={({ target: { value } }) => setActionInterval(value)}
218
228
  />
219
229
  </Input.Root>
220
- <Timer className={mx('absolute inline-end-1 block-start-1 mt-[6px]', getSize(3))} />
230
+ <Icon icon='ph--timer--regular' classNames={mx('absolute inline-end-1 block-start-1 mt-[6px]', getSize(3))} />
221
231
  </div>
222
- <Button onClick={() => action && runAction(client, action)}>
223
- <Plus />
224
- </Button>
232
+ <IconButton icon='ph--plus--regular' label='Add' onClick={() => action && runAction(client, action)} />
225
233
  <Select.Root value={action?.toString()} onValueChange={(action) => setAction(action as unknown as Action)}>
226
234
  <Select.TriggerButton placeholder='Select value' />
227
235
  <Select.Portal>
@@ -245,28 +253,30 @@ const Controls = ({ children }: PropsWithChildren) => {
245
253
  );
246
254
  };
247
255
 
248
- const meta: Meta = {
256
+ const meta = {
249
257
  title: 'sdk/app-graph/EchoGraph',
250
258
  decorators: [
259
+ withTheme,
251
260
  withClientProvider({
252
261
  createIdentity: true,
253
- onIdentityCreated: async ({ client }) => {
262
+ onCreateIdentity: async ({ client }) => {
254
263
  await client.spaces.create();
255
264
  await client.spaces.create();
256
265
  },
257
266
  }),
258
- withTheme,
259
267
  ],
260
- };
268
+ } satisfies Meta;
261
269
 
262
270
  export default meta;
263
271
 
264
- export const JsonView = {
272
+ type Story = StoryObj<typeof meta>;
273
+
274
+ export const JsonView: Story = {
265
275
  render: () => {
266
276
  const client = useClient();
267
277
  const registry = useContext(RegistryContext);
268
278
  const graph = useMemo(() => createGraph(client, registry), [client, registry]);
269
- const data = useRxValue(graph.json());
279
+ const data = useAtomValue(graph.json());
270
280
 
271
281
  return (
272
282
  <>
@@ -277,7 +287,7 @@ export const JsonView = {
277
287
  },
278
288
  };
279
289
 
280
- export const TreeView = {
290
+ export const TreeView: Story = {
281
291
  render: () => {
282
292
  const client = useClient();
283
293
  const registry = useContext(RegistryContext);
@@ -286,7 +296,7 @@ export const TreeView = {
286
296
 
287
297
  const useItems = useCallback(
288
298
  (node?: Node, options?: { disposition?: string; sort?: boolean }) => {
289
- const connections = useRxValue(graph.connections(node?.id ?? ROOT_ID));
299
+ const connections = useAtomValue(graph.connections(node?.id ?? ROOT_ID));
290
300
  return options?.sort ? connections.toSorted((a, b) => byPosition(a.properties, b.properties)) : connections;
291
301
  },
292
302
  [graph],
@@ -72,7 +72,7 @@ const Scalar: FC<{ value: any }> = ({ value }) => {
72
72
 
73
73
  const Box: FC<HTMLAttributes<HTMLDivElement>> = ({ children, className, ...props }) => {
74
74
  return (
75
- <div className={mx('flex px-2 border border-l-0 font-mono truncate', className)} {...props}>
75
+ <div className={mx('flex pli-2 border border-l-0 font-mono truncate', className)} {...props}>
76
76
  {children}
77
77
  </div>
78
78
  );
package/src/testing.ts CHANGED
@@ -2,13 +2,13 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Rx } from '@effect-rx/rx-react';
5
+ import { Atom } from '@effect-atom/atom-react';
6
6
 
7
+ import { type AnyEchoObject } from '@dxos/echo/internal';
7
8
  import { type QueryResult } from '@dxos/echo-db';
8
- import { type AnyEchoObject } from '@dxos/echo-schema';
9
9
 
10
- export const rxFromQuery = <T extends AnyEchoObject>(query: QueryResult<T>): Rx.Rx<T[]> => {
11
- return Rx.make((get) => {
10
+ export const atomFromQuery = <T extends AnyEchoObject>(query: QueryResult<T>): Atom.Atom<T[]> => {
11
+ return Atom.make((get) => {
12
12
  const unsubscribe = query.subscribe((result) => {
13
13
  get.setSelf(result.objects);
14
14
  });