@dxos/app-graph 0.6.11-staging.e6894a4 → 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
|
|
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
|
|
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
|
|
30
|
-
"@dxos/
|
|
31
|
-
"@dxos/
|
|
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
|
|
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
|
|
45
|
-
"@dxos/react-
|
|
46
|
-
"@dxos/react-ui
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
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 {
|
|
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
|
-
|
|
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
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
258
|
-
|
|
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 = {};
|