@dxos/app-graph 0.6.11-staging.a542fc9 → 0.6.11

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.
@@ -3,9 +3,8 @@ import React from 'react';
3
3
  declare const _default: {
4
4
  title: string;
5
5
  decorators: import("@storybook/react/*").Decorator[];
6
- };
7
- export default _default;
8
- export declare const Default: {
9
6
  render: () => React.JSX.Element;
10
7
  };
8
+ export default _default;
9
+ export declare const Default: {};
11
10
  //# sourceMappingURL=EchoGraph.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EchoGraph.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/EchoGraph.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAGrB,OAAO,KAA8B,MAAM,OAAO,CAAC;;;;;AAyBnD,wBAGE;AA6NF,eAAO,MAAM,OAAO;;CAEnB,CAAC"}
1
+ {"version":3,"file":"EchoGraph.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/EchoGraph.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAGrB,OAAO,KAA8B,MAAM,OAAO,CAAC;;;;;;AA0PnD,wBAaE;AAEF,eAAO,MAAM,OAAO,IAAK,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/app-graph",
3
- "version": "0.6.11-staging.a542fc9",
3
+ "version": "0.6.11",
4
4
  "description": "Constructs knowledge graphs for the purpose of building applications on top of",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -26,13 +26,13 @@
26
26
  "dependencies": {
27
27
  "@preact/signals-core": "^1.6.0",
28
28
  "main-thread-scheduling": "^14.1.1",
29
- "@dxos/async": "0.6.11-staging.a542fc9",
30
- "@dxos/debug": "0.6.11-staging.a542fc9",
31
- "@dxos/echo-schema": "0.6.11-staging.a542fc9",
32
- "@dxos/echo-signals": "0.6.11-staging.a542fc9",
33
- "@dxos/util": "0.6.11-staging.a542fc9",
34
- "@dxos/invariant": "0.6.11-staging.a542fc9",
35
- "@dxos/log": "0.6.11-staging.a542fc9"
29
+ "@dxos/async": "0.6.11",
30
+ "@dxos/debug": "0.6.11",
31
+ "@dxos/echo-schema": "0.6.11",
32
+ "@dxos/echo-signals": "0.6.11",
33
+ "@dxos/invariant": "0.6.11",
34
+ "@dxos/log": "0.6.11",
35
+ "@dxos/util": "0.6.11"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@phosphor-icons/react": "^2.1.5",
@@ -41,11 +41,11 @@
41
41
  "react": "~18.2.0",
42
42
  "react-dom": "~18.2.0",
43
43
  "vite": "^5.3.4",
44
- "@dxos/random": "0.6.11-staging.a542fc9",
45
- "@dxos/react-client": "0.6.11-staging.a542fc9",
46
- "@dxos/storybook-utils": "0.6.11-staging.a542fc9",
47
- "@dxos/react-ui-theme": "0.6.11-staging.a542fc9",
48
- "@dxos/react-ui": "0.6.11-staging.a542fc9"
44
+ "@dxos/random": "0.6.11",
45
+ "@dxos/react-client": "0.6.11",
46
+ "@dxos/react-ui": "0.6.11",
47
+ "@dxos/react-ui-theme": "0.6.11",
48
+ "@dxos/storybook-utils": "0.6.11"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "react": "^18.0.0",
@@ -10,7 +10,7 @@ import React, { useEffect, useState } from 'react';
10
10
  import { type EchoReactiveObject, create } from '@dxos/echo-schema';
11
11
  import { registerSignalRuntime } from '@dxos/echo-signals';
12
12
  import { faker } from '@dxos/random';
13
- import { Client } from '@dxos/react-client';
13
+ import { type Client, useClient } from '@dxos/react-client';
14
14
  import {
15
15
  type Space,
16
16
  SpaceState,
@@ -20,32 +20,40 @@ import {
20
20
  type QueryOptions,
21
21
  type Query,
22
22
  } from '@dxos/react-client/echo';
23
- import { ClientRepeater, TestBuilder } from '@dxos/react-client/testing';
24
- import { Button, DensityProvider, Input, Select } from '@dxos/react-ui';
23
+ import { withClientProvider } from '@dxos/react-client/testing';
24
+ import { Button, DensityProvider, Input, Select, useAsyncEffect } from '@dxos/react-ui';
25
25
  import { getSize, mx } from '@dxos/react-ui-theme';
26
26
  import { withTheme } from '@dxos/storybook-utils';
27
27
  import { safeParseInt } from '@dxos/util';
28
28
 
29
29
  import { Tree } from './Tree';
30
+ import { type Graph } from '../graph';
30
31
  import { GraphBuilder, cleanup, createExtension, memoize, toSignal } from '../graph-builder';
31
32
  import { type Node } from '../node';
32
33
 
33
- export default {
34
- title: 'app-graph/EchoGraph',
35
- decorators: [withTheme],
36
- };
37
-
38
34
  const DEFAULT_PERIOD = 500;
39
35
 
36
+ const EMPTY_ARRAY: never[] = [];
37
+
40
38
  registerSignalRuntime();
41
- const testBuilder = new TestBuilder();
42
- const client = new Client({ services: testBuilder.createLocalClientServices() });
43
- await client.initialize();
44
- await client.halo.createIdentity();
45
- await client.spaces.create();
46
- await client.spaces.create();
47
39
 
48
- const EMPTY_ARRAY: never[] = [];
40
+ enum Action {
41
+ CREATE_SPACE = 'CREATE_SPACE',
42
+ CLOSE_SPACE = 'CLOSE_SPACE',
43
+ RENAME_SPACE = 'RENAME_SPACE',
44
+ ADD_OBJECT = 'ADD_OBJECT',
45
+ REMOVE_OBJECT = 'REMOVE_OBJECT',
46
+ RENAME_OBJECT = 'RENAME_OBJECT',
47
+ }
48
+
49
+ const actionWeights = {
50
+ [Action.CREATE_SPACE]: 2,
51
+ [Action.CLOSE_SPACE]: 1,
52
+ [Action.RENAME_SPACE]: 2,
53
+ [Action.ADD_OBJECT]: 4,
54
+ [Action.REMOVE_OBJECT]: 3,
55
+ [Action.RENAME_OBJECT]: 4,
56
+ };
49
57
 
50
58
  // TODO(wittjosiah): Factor out.
51
59
  const memoizeQuery = <T extends EchoReactiveObject<any>>(
@@ -67,67 +75,52 @@ const memoizeQuery = <T extends EchoReactiveObject<any>>(
67
75
  return query?.objects ?? EMPTY_ARRAY;
68
76
  };
69
77
 
70
- const spaceBuilderExtension = createExtension({
71
- id: 'space',
72
- filter: (node): node is Node<null> => node.id === 'root',
73
- connector: ({ node }) => {
74
- const spaces = toSignal(
75
- (onChange) => client.spaces.subscribe(() => onChange()).unsubscribe,
76
- () => client.spaces.get(),
77
- );
78
- if (!spaces) {
79
- return;
80
- }
78
+ const createGraph = async (client: Client): Promise<Graph> => {
79
+ const spaceBuilderExtension = createExtension({
80
+ id: 'space',
81
+ filter: (node): node is Node<null> => node.id === 'root',
82
+ connector: ({ node }) => {
83
+ const spaces = toSignal(
84
+ (onChange) => client.spaces.subscribe(() => onChange()).unsubscribe,
85
+ () => client.spaces.get(),
86
+ );
87
+ if (!spaces) {
88
+ return;
89
+ }
81
90
 
82
- return spaces
83
- .filter((space) => space.state.get() === SpaceState.SPACE_READY)
84
- .map((space) => ({
85
- id: space.id,
86
- type: 'dxos.org/type/Space',
87
- properties: { label: space.properties.name },
88
- data: space,
91
+ return spaces
92
+ .filter((space) => space.state.get() === SpaceState.SPACE_READY)
93
+ .map((space) => ({
94
+ id: space.id,
95
+ type: 'dxos.org/type/Space',
96
+ properties: { label: space.properties.name },
97
+ data: space,
98
+ }));
99
+ },
100
+ });
101
+
102
+ const objectBuilderExtension = createExtension({
103
+ id: 'object',
104
+ filter: (node): node is Node<Space> => isSpace(node.data),
105
+ connector: ({ node }) => {
106
+ const objects = memoizeQuery(node.data, { type: 'test' });
107
+ return objects.map((object) => ({
108
+ id: object.id,
109
+ type: 'dxos.org/type/test',
110
+ properties: { label: object.name },
111
+ data: object,
89
112
  }));
90
- },
91
- });
92
-
93
- const objectBuilderExtension = createExtension({
94
- id: 'object',
95
- filter: (node): node is Node<Space> => isSpace(node.data),
96
- connector: ({ node }) => {
97
- const objects = memoizeQuery(node.data, { type: 'test' });
98
- return objects.map((object) => ({
99
- id: object.id,
100
- type: 'dxos.org/type/test',
101
- properties: { label: object.name },
102
- data: object,
103
- }));
104
- },
105
- });
106
-
107
- const graph = new GraphBuilder().addExtension(spaceBuilderExtension).addExtension(objectBuilderExtension).graph;
108
-
109
- graph.subscribeTraverse({
110
- visitor: (node) => {
111
- void graph.expand(node);
112
- },
113
- });
113
+ },
114
+ });
114
115
 
115
- enum Action {
116
- CREATE_SPACE = 'CREATE_SPACE',
117
- CLOSE_SPACE = 'CLOSE_SPACE',
118
- RENAME_SPACE = 'RENAME_SPACE',
119
- ADD_OBJECT = 'ADD_OBJECT',
120
- REMOVE_OBJECT = 'REMOVE_OBJECT',
121
- RENAME_OBJECT = 'RENAME_OBJECT',
122
- }
116
+ const graph = new GraphBuilder().addExtension(spaceBuilderExtension).addExtension(objectBuilderExtension).graph;
117
+ graph.subscribeTraverse({
118
+ visitor: (node) => {
119
+ void graph.expand(node);
120
+ },
121
+ });
123
122
 
124
- const actionWeights = {
125
- [Action.CREATE_SPACE]: 2,
126
- [Action.CLOSE_SPACE]: 1,
127
- [Action.RENAME_SPACE]: 2,
128
- [Action.ADD_OBJECT]: 4,
129
- [Action.REMOVE_OBJECT]: 3,
130
- [Action.RENAME_OBJECT]: 4,
123
+ return graph;
131
124
  };
132
125
 
133
126
  const randomAction = () => {
@@ -138,31 +131,30 @@ const randomAction = () => {
138
131
  return actionDistribution[Math.floor(Math.random() * actionDistribution.length)];
139
132
  };
140
133
 
141
- const getRandomSpace = (): Space | undefined => {
134
+ const getRandomSpace = (client: Client): Space | undefined => {
142
135
  const spaces = client.spaces.get().filter((space) => space.state.get() === SpaceState.SPACE_READY);
143
- const space = spaces[Math.floor(Math.random() * spaces.length)];
144
- return space;
136
+ return spaces[Math.floor(Math.random() * spaces.length)];
145
137
  };
146
138
 
147
- const getSpaceWithObjects = async (): Promise<Space | undefined> => {
139
+ const getSpaceWithObjects = async (client: Client): Promise<Space | undefined> => {
148
140
  const readySpaces = client.spaces.get().filter((space) => space.state.get() === SpaceState.SPACE_READY);
149
141
  const spaceQueries = await Promise.all(readySpaces.map((space) => space.db.query({ type: 'test' }).run()));
150
142
  const spaces = readySpaces.filter((space, index) => spaceQueries[index].objects.length > 0);
151
143
  return spaces[Math.floor(Math.random() * spaces.length)];
152
144
  };
153
145
 
154
- const runAction = async (action: Action) => {
146
+ const runAction = async (client: Client, action: Action) => {
155
147
  switch (action) {
156
148
  case Action.CREATE_SPACE:
157
149
  void client.spaces.create();
158
150
  break;
159
151
 
160
152
  case Action.CLOSE_SPACE:
161
- void getRandomSpace()?.close();
153
+ void getRandomSpace(client)?.close();
162
154
  break;
163
155
 
164
156
  case Action.RENAME_SPACE: {
165
- const space = getRandomSpace();
157
+ const space = getRandomSpace(client);
166
158
  if (space) {
167
159
  space.properties.name = faker.commerce.productName();
168
160
  }
@@ -170,11 +162,11 @@ const runAction = async (action: Action) => {
170
162
  }
171
163
 
172
164
  case Action.ADD_OBJECT:
173
- getRandomSpace()?.db.add(create({ type: 'test', name: faker.commerce.productName() }));
165
+ getRandomSpace(client)?.db.add(create({ type: 'test', name: faker.commerce.productName() }));
174
166
  break;
175
167
 
176
168
  case Action.REMOVE_OBJECT: {
177
- const space = await getSpaceWithObjects();
169
+ const space = await getSpaceWithObjects(client);
178
170
  if (space) {
179
171
  const { objects } = await space.db.query({ type: 'test' }).run();
180
172
  space.db.remove(objects[Math.floor(Math.random() * objects.length)]);
@@ -183,7 +175,7 @@ const runAction = async (action: Action) => {
183
175
  }
184
176
 
185
177
  case Action.RENAME_OBJECT: {
186
- const space = await getSpaceWithObjects();
178
+ const space = await getSpaceWithObjects(client);
187
179
  if (space) {
188
180
  const { objects } = await space.db.query({ type: 'test' }).run();
189
181
  objects[Math.floor(Math.random() * objects.length)].name = faker.commerce.productName();
@@ -193,19 +185,28 @@ const runAction = async (action: Action) => {
193
185
  }
194
186
  };
195
187
 
196
- const EchoGraphStory = () => {
188
+ const Story = () => {
197
189
  const [generating, setGenerating] = useState(false);
198
190
  const [actionInterval, setActionInterval] = useState(String(DEFAULT_PERIOD));
199
191
  const [action, setAction] = useState<Action>();
200
192
 
193
+ const client = useClient();
194
+ const [graph, setGraph] = useState<Graph>();
195
+ useAsyncEffect(async () => {
196
+ setGraph(await createGraph(client));
197
+ }, [client]);
198
+
201
199
  useEffect(() => {
202
200
  if (!generating) {
203
201
  return;
204
202
  }
205
203
 
206
- const interval = setInterval(() => runAction(randomAction()), safeParseInt(actionInterval) ?? DEFAULT_PERIOD);
204
+ const interval = setInterval(
205
+ () => runAction(client, randomAction()),
206
+ safeParseInt(actionInterval) ?? DEFAULT_PERIOD,
207
+ );
207
208
  return () => clearInterval(interval);
208
- }, [generating, actionInterval]);
209
+ }, [client, generating, actionInterval]);
209
210
 
210
211
  return (
211
212
  <>
@@ -227,7 +228,7 @@ const EchoGraphStory = () => {
227
228
  </Input.Root>
228
229
  <Timer className={mx('absolute inline-end-1 block-start-1 mt-[6px]', getSize(3))} />
229
230
  </div>
230
- <Button onClick={() => action && runAction(action)}>
231
+ <Button onClick={() => action && runAction(client, action)}>
231
232
  <Plus />
232
233
  </Button>
233
234
  <Select.Root value={action?.toString()} onValueChange={(action) => setAction(action as unknown as Action)}>
@@ -249,11 +250,24 @@ const EchoGraphStory = () => {
249
250
  </Select.Root>
250
251
  </DensityProvider>
251
252
  </div>
252
- <Tree data={graph.toJSON()} />
253
+ {graph && <Tree data={graph.toJSON()} />}
253
254
  </>
254
255
  );
255
256
  };
256
257
 
257
- export const Default = {
258
- render: () => <ClientRepeater component={EchoGraphStory} clients={[client]} className='flex flex-col' />,
258
+ export default {
259
+ title: 'app-graph/EchoGraph',
260
+ decorators: [
261
+ withTheme,
262
+ withClientProvider({
263
+ createIdentity: true,
264
+ onInitialized: async (client: Client) => {
265
+ await client.spaces.create();
266
+ await client.spaces.create();
267
+ },
268
+ }),
269
+ ],
270
+ render: Story,
259
271
  };
272
+
273
+ export const Default = {};