@dxos/app-graph 0.6.3-main.9e4e207 → 0.6.3-main.a95c491
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.
- package/dist/lib/browser/index.mjs +76 -85
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +75 -84
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +10 -10
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/graph-builder.test.ts +30 -18
- package/src/graph-builder.ts +30 -35
- package/src/graph.ts +54 -54
- package/src/stories/EchoGraph.stories.tsx +10 -4
|
@@ -7,7 +7,7 @@ export declare const ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
|
|
|
7
7
|
export type NodesOptions<T = any, U extends Record<string, any> = Record<string, any>> = {
|
|
8
8
|
relation?: Relation;
|
|
9
9
|
filter?: NodeFilter<T, U>;
|
|
10
|
-
|
|
10
|
+
expansion?: boolean;
|
|
11
11
|
type?: string;
|
|
12
12
|
};
|
|
13
13
|
export type GraphTraversalOptions = {
|
|
@@ -30,9 +30,9 @@ export type GraphTraversalOptions = {
|
|
|
30
30
|
*/
|
|
31
31
|
relation?: Relation;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Allow traversal to trigger expansion of the graph via `onInitialNodes`.
|
|
34
34
|
*/
|
|
35
|
-
|
|
35
|
+
expansion?: boolean;
|
|
36
36
|
};
|
|
37
37
|
/**
|
|
38
38
|
* The Graph represents the structure of the application constructed via plugins.
|
|
@@ -60,10 +60,9 @@ export declare class Graph {
|
|
|
60
60
|
/**
|
|
61
61
|
* Convert the graph to a JSON object.
|
|
62
62
|
*/
|
|
63
|
-
toJSON({ id, maxLength
|
|
63
|
+
toJSON({ id, maxLength }?: {
|
|
64
64
|
id?: string;
|
|
65
65
|
maxLength?: number;
|
|
66
|
-
onlyLoaded?: boolean;
|
|
67
66
|
}): any;
|
|
68
67
|
/**
|
|
69
68
|
* Find the node with the given id in the graph.
|
|
@@ -71,7 +70,7 @@ export declare class Graph {
|
|
|
71
70
|
* If a node is not found within the graph and an `onInitialNode` callback is provided,
|
|
72
71
|
* it is called with the id and type of the node, potentially initializing the node.
|
|
73
72
|
*/
|
|
74
|
-
findNode(id: string
|
|
73
|
+
findNode(id: string): Node | undefined;
|
|
75
74
|
/**
|
|
76
75
|
* Wait for a node to be added to the graph.
|
|
77
76
|
*
|
|
@@ -99,14 +98,15 @@ export declare class Graph {
|
|
|
99
98
|
/**
|
|
100
99
|
* Actions or action groups that this node is connected to in default order.
|
|
101
100
|
*/
|
|
102
|
-
actions(node: Node, {
|
|
103
|
-
|
|
101
|
+
actions(node: Node, { expansion }?: {
|
|
102
|
+
expansion?: boolean;
|
|
104
103
|
}): Readonly<{
|
|
105
104
|
id: string;
|
|
106
105
|
type: string;
|
|
107
106
|
properties: Readonly<Record<string, any>>;
|
|
108
107
|
data: any;
|
|
109
108
|
}>[];
|
|
109
|
+
expand(node: Node, relation?: Relation, type?: string): Promise<void>;
|
|
110
110
|
/**
|
|
111
111
|
* Recursive depth-first traversal of the graph.
|
|
112
112
|
*
|
|
@@ -114,7 +114,7 @@ export declare class Graph {
|
|
|
114
114
|
* @param options.relation The relation to traverse graph edges.
|
|
115
115
|
* @param options.visitor A callback which is called for each node visited during traversal.
|
|
116
116
|
*/
|
|
117
|
-
traverse({ visitor, node, relation,
|
|
117
|
+
traverse({ visitor, node, relation, expansion }: GraphTraversalOptions, path?: string[]): void;
|
|
118
118
|
/**
|
|
119
119
|
* Recursive depth-first traversal of the graph wrapping each visitor call in an effect.
|
|
120
120
|
*
|
|
@@ -122,7 +122,7 @@ export declare class Graph {
|
|
|
122
122
|
* @param options.relation The relation to traverse graph edges.
|
|
123
123
|
* @param options.visitor A callback which is called for each node visited during traversal.
|
|
124
124
|
*/
|
|
125
|
-
subscribeTraverse({ visitor, node, relation,
|
|
125
|
+
subscribeTraverse({ visitor, node, relation, expansion }: GraphTraversalOptions, currentPath?: string[]): () => void;
|
|
126
126
|
/**
|
|
127
127
|
* Get the path between two nodes in the graph.
|
|
128
128
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/graph.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,IAAI,EAAgB,KAAK,UAAU,EAAgB,MAAM,QAAQ,CAAC;AAM/F,eAAO,MAAM,QAAQ,SAAU,IAAI,KAAG,KAIrC,CAAC;AAEF,eAAO,MAAM,OAAO,SAAS,CAAC;AAC9B,eAAO,MAAM,SAAS,4BAA4B,CAAC;AACnD,eAAO,MAAM,WAAW,8BAA8B,CAAC;AACvD,eAAO,MAAM,iBAAiB,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EchoGraph.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/EchoGraph.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;;;;;AA4BpB,wBAGE;
|
|
1
|
+
{"version":3,"file":"EchoGraph.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/EchoGraph.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;;;;;AA4BpB,wBAGE;AA6NF,eAAO,MAAM,OAAO;;CAEnB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/app-graph",
|
|
3
|
-
"version": "0.6.3-main.
|
|
3
|
+
"version": "0.6.3-main.a95c491",
|
|
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",
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@preact/signals-core": "^1.6.0",
|
|
24
24
|
"main-thread-scheduling": "^14.1.1",
|
|
25
|
-
"@dxos/
|
|
26
|
-
"@dxos/
|
|
27
|
-
"@dxos/echo-
|
|
28
|
-
"@dxos/
|
|
29
|
-
"@dxos/
|
|
30
|
-
"@dxos/log": "0.6.3-main.
|
|
31
|
-
"@dxos/util": "0.6.3-main.
|
|
25
|
+
"@dxos/async": "0.6.3-main.a95c491",
|
|
26
|
+
"@dxos/debug": "0.6.3-main.a95c491",
|
|
27
|
+
"@dxos/echo-schema": "0.6.3-main.a95c491",
|
|
28
|
+
"@dxos/invariant": "0.6.3-main.a95c491",
|
|
29
|
+
"@dxos/echo-signals": "0.6.3-main.a95c491",
|
|
30
|
+
"@dxos/log": "0.6.3-main.a95c491",
|
|
31
|
+
"@dxos/util": "0.6.3-main.a95c491"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@phosphor-icons/react": "^2.1.5",
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"react": "^18.2.0",
|
|
38
38
|
"react-dom": "^18.2.0",
|
|
39
39
|
"vite": "^5.2.9",
|
|
40
|
-
"@dxos/react-client": "0.6.3-main.
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/react-ui
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/storybook-utils": "0.6.3-main.
|
|
40
|
+
"@dxos/react-client": "0.6.3-main.a95c491",
|
|
41
|
+
"@dxos/random": "0.6.3-main.a95c491",
|
|
42
|
+
"@dxos/react-ui": "0.6.3-main.a95c491",
|
|
43
|
+
"@dxos/react-ui-theme": "0.6.3-main.a95c491",
|
|
44
|
+
"@dxos/storybook-utils": "0.6.3-main.a95c491"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"react": "^18.2.0",
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { signal } from '@preact/signals-core';
|
|
6
|
-
import { expect } from 'chai';
|
|
6
|
+
import chai, { expect } from 'chai';
|
|
7
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
7
8
|
|
|
8
9
|
import { describe, test } from '@dxos/test';
|
|
9
10
|
|
|
@@ -11,13 +12,15 @@ import { ACTION_TYPE } from './graph';
|
|
|
11
12
|
import { GraphBuilder, createExtension, memoize } from './graph-builder';
|
|
12
13
|
import { type Node } from './node';
|
|
13
14
|
|
|
15
|
+
chai.use(chaiAsPromised);
|
|
16
|
+
|
|
14
17
|
const exampleId = (id: number) => `dx:test:${id}`;
|
|
15
18
|
const EXAMPLE_ID = exampleId(1);
|
|
16
19
|
const EXAMPLE_TYPE = 'dxos.org/type/example';
|
|
17
20
|
|
|
18
21
|
describe('GraphBuilder', () => {
|
|
19
22
|
describe('resolver', () => {
|
|
20
|
-
test('works', () => {
|
|
23
|
+
test('works', async () => {
|
|
21
24
|
const builder = new GraphBuilder();
|
|
22
25
|
const graph = builder.graph;
|
|
23
26
|
|
|
@@ -31,14 +34,14 @@ describe('GraphBuilder', () => {
|
|
|
31
34
|
);
|
|
32
35
|
|
|
33
36
|
{
|
|
34
|
-
const node = graph.
|
|
37
|
+
const node = await graph.waitForNode(EXAMPLE_ID);
|
|
35
38
|
expect(node?.id).to.equal(EXAMPLE_ID);
|
|
36
39
|
expect(node?.type).to.equal(EXAMPLE_TYPE);
|
|
37
40
|
expect(node?.data).to.equal(1);
|
|
38
41
|
}
|
|
39
42
|
});
|
|
40
43
|
|
|
41
|
-
test('updates', () => {
|
|
44
|
+
test('updates', async () => {
|
|
42
45
|
const builder = new GraphBuilder();
|
|
43
46
|
const name = signal('default');
|
|
44
47
|
builder.addExtension(
|
|
@@ -46,14 +49,14 @@ describe('GraphBuilder', () => {
|
|
|
46
49
|
);
|
|
47
50
|
const graph = builder.graph;
|
|
48
51
|
|
|
49
|
-
const node = graph.
|
|
52
|
+
const node = await graph.waitForNode(EXAMPLE_ID);
|
|
50
53
|
expect(node?.data).to.equal('default');
|
|
51
54
|
|
|
52
55
|
name.value = 'updated';
|
|
53
56
|
expect(node?.data).to.equal('updated');
|
|
54
57
|
});
|
|
55
58
|
|
|
56
|
-
test('memoize', () => {
|
|
59
|
+
test('memoize', async () => {
|
|
57
60
|
const builder = new GraphBuilder();
|
|
58
61
|
const name = signal('default');
|
|
59
62
|
let count = 0;
|
|
@@ -73,7 +76,7 @@ describe('GraphBuilder', () => {
|
|
|
73
76
|
);
|
|
74
77
|
const graph = builder.graph;
|
|
75
78
|
|
|
76
|
-
const node = graph.
|
|
79
|
+
const node = await graph.waitForNode(EXAMPLE_ID);
|
|
77
80
|
expect(node?.data).to.equal('default');
|
|
78
81
|
expect(count).to.equal(1);
|
|
79
82
|
expect(memoizedCount).to.equal(1);
|
|
@@ -89,9 +92,8 @@ describe('GraphBuilder', () => {
|
|
|
89
92
|
});
|
|
90
93
|
|
|
91
94
|
describe('connector', () => {
|
|
92
|
-
test('works', () => {
|
|
95
|
+
test('works', async () => {
|
|
93
96
|
const builder = new GraphBuilder();
|
|
94
|
-
const graph = builder.graph;
|
|
95
97
|
builder.addExtension(
|
|
96
98
|
createExtension({
|
|
97
99
|
id: 'outbound-connector',
|
|
@@ -106,6 +108,10 @@ describe('GraphBuilder', () => {
|
|
|
106
108
|
}),
|
|
107
109
|
);
|
|
108
110
|
|
|
111
|
+
const graph = builder.graph;
|
|
112
|
+
await graph.expand(graph.root);
|
|
113
|
+
await graph.expand(graph.root, 'inbound');
|
|
114
|
+
|
|
109
115
|
const outbound = graph.nodes(graph.root);
|
|
110
116
|
const inbound = graph.nodes(graph.root, { relation: 'inbound' });
|
|
111
117
|
|
|
@@ -117,7 +123,7 @@ describe('GraphBuilder', () => {
|
|
|
117
123
|
expect(inbound?.[0].data).to.equal(0);
|
|
118
124
|
});
|
|
119
125
|
|
|
120
|
-
test('updates', () => {
|
|
126
|
+
test('updates', async () => {
|
|
121
127
|
const name = signal('default');
|
|
122
128
|
const builder = new GraphBuilder();
|
|
123
129
|
builder.addExtension(
|
|
@@ -127,6 +133,7 @@ describe('GraphBuilder', () => {
|
|
|
127
133
|
}),
|
|
128
134
|
);
|
|
129
135
|
const graph = builder.graph;
|
|
136
|
+
await graph.expand(graph.root);
|
|
130
137
|
|
|
131
138
|
const [node] = graph.nodes(graph.root);
|
|
132
139
|
expect(node.properties.label).to.equal('default');
|
|
@@ -135,7 +142,7 @@ describe('GraphBuilder', () => {
|
|
|
135
142
|
expect(node.properties.label).to.equal('updated');
|
|
136
143
|
});
|
|
137
144
|
|
|
138
|
-
test('removes', () => {
|
|
145
|
+
test('removes', async () => {
|
|
139
146
|
const nodes = signal([
|
|
140
147
|
{ id: exampleId(1), type: EXAMPLE_TYPE, data: 1 },
|
|
141
148
|
{ id: exampleId(2), type: EXAMPLE_TYPE, data: 2 },
|
|
@@ -149,6 +156,7 @@ describe('GraphBuilder', () => {
|
|
|
149
156
|
}),
|
|
150
157
|
);
|
|
151
158
|
const graph = builder.graph;
|
|
159
|
+
await graph.expand(graph.root);
|
|
152
160
|
|
|
153
161
|
{
|
|
154
162
|
const nodes = graph.nodes(graph.root);
|
|
@@ -166,7 +174,7 @@ describe('GraphBuilder', () => {
|
|
|
166
174
|
}
|
|
167
175
|
});
|
|
168
176
|
|
|
169
|
-
test('filters by type', () => {
|
|
177
|
+
test('filters by type', async () => {
|
|
170
178
|
const builder = new GraphBuilder();
|
|
171
179
|
builder.addExtension(
|
|
172
180
|
createExtension({
|
|
@@ -177,21 +185,22 @@ describe('GraphBuilder', () => {
|
|
|
177
185
|
);
|
|
178
186
|
const graph = builder.graph;
|
|
179
187
|
|
|
188
|
+
await graph.expand(graph.root, 'outbound', ACTION_TYPE);
|
|
180
189
|
const actions = graph.actions(graph.root);
|
|
181
190
|
expect(actions).has.length(1);
|
|
182
191
|
expect(actions?.[0].id).to.equal('action');
|
|
183
192
|
expect(actions?.[0].type).to.equal(ACTION_TYPE);
|
|
184
193
|
|
|
185
|
-
|
|
186
|
-
expect(node).to.be.undefined;
|
|
194
|
+
await expect(graph.waitForNode('not-action', 10)).to.be.rejected;
|
|
187
195
|
|
|
196
|
+
await graph.expand(graph.root);
|
|
188
197
|
const nodes = graph.nodes(graph.root);
|
|
189
198
|
expect(nodes).has.length(1);
|
|
190
199
|
expect(nodes?.[0].id).to.equal('not-action');
|
|
191
200
|
expect(nodes?.[0].data).to.equal(1);
|
|
192
201
|
});
|
|
193
202
|
|
|
194
|
-
test('filters by callback', () => {
|
|
203
|
+
test('filters by callback', async () => {
|
|
195
204
|
const builder = new GraphBuilder();
|
|
196
205
|
builder.addExtension(
|
|
197
206
|
createExtension({
|
|
@@ -201,6 +210,7 @@ describe('GraphBuilder', () => {
|
|
|
201
210
|
}),
|
|
202
211
|
);
|
|
203
212
|
const graph = builder.graph;
|
|
213
|
+
await graph.expand(graph.root);
|
|
204
214
|
|
|
205
215
|
const [node1] = graph.nodes(graph.root);
|
|
206
216
|
expect(node1?.id).to.equal(EXAMPLE_ID);
|
|
@@ -209,7 +219,7 @@ describe('GraphBuilder', () => {
|
|
|
209
219
|
expect(nodes).has.length(0);
|
|
210
220
|
});
|
|
211
221
|
|
|
212
|
-
test('memoize', () => {
|
|
222
|
+
test('memoize', async () => {
|
|
213
223
|
const builder = new GraphBuilder();
|
|
214
224
|
const name = signal('default');
|
|
215
225
|
let count = 0;
|
|
@@ -228,6 +238,7 @@ describe('GraphBuilder', () => {
|
|
|
228
238
|
}),
|
|
229
239
|
);
|
|
230
240
|
const graph = builder.graph;
|
|
241
|
+
await graph.expand(graph.root);
|
|
231
242
|
|
|
232
243
|
const [node] = graph.nodes(graph.root);
|
|
233
244
|
expect(node.properties.label).to.equal('default');
|
|
@@ -271,7 +282,7 @@ describe('GraphBuilder', () => {
|
|
|
271
282
|
});
|
|
272
283
|
|
|
273
284
|
describe('multiples', () => {
|
|
274
|
-
test('one of each with multiple memos', () => {
|
|
285
|
+
test('one of each with multiple memos', async () => {
|
|
275
286
|
const name = signal('default');
|
|
276
287
|
const builder = new GraphBuilder();
|
|
277
288
|
builder.addExtension(
|
|
@@ -291,8 +302,9 @@ describe('GraphBuilder', () => {
|
|
|
291
302
|
);
|
|
292
303
|
const graph = builder.graph;
|
|
293
304
|
|
|
294
|
-
const one = graph.
|
|
305
|
+
const one = await graph.waitForNode(EXAMPLE_ID);
|
|
295
306
|
const initialData = one!.data;
|
|
307
|
+
await graph.expand(one!);
|
|
296
308
|
const two = graph.nodes(one!)[0];
|
|
297
309
|
const initialA = two?.data.a;
|
|
298
310
|
const initialB = two?.data.b;
|
package/src/graph-builder.ts
CHANGED
|
@@ -194,7 +194,7 @@ export class GraphBuilder {
|
|
|
194
194
|
|
|
195
195
|
constructor() {
|
|
196
196
|
this._graph = new Graph({
|
|
197
|
-
onInitialNode: (id
|
|
197
|
+
onInitialNode: (id) => this._onInitialNode(id),
|
|
198
198
|
onInitialNodes: (node, relation, type) => this._onInitialNodes(node, relation, type),
|
|
199
199
|
onRemoveNode: (id) => this._onRemoveNode(id),
|
|
200
200
|
});
|
|
@@ -263,11 +263,11 @@ export class GraphBuilder {
|
|
|
263
263
|
await Promise.all(nodes.map((n) => this.traverse({ node: n, relation, visitor }, [...path, node.id])));
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
-
private _onInitialNode(nodeId: string
|
|
266
|
+
private async _onInitialNode(nodeId: string) {
|
|
267
267
|
this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? signal({});
|
|
268
|
-
let
|
|
269
|
-
for (const { id,
|
|
270
|
-
if (
|
|
268
|
+
let resolved = false;
|
|
269
|
+
for (const { id, resolver } of Object.values(this._extensions)) {
|
|
270
|
+
if (resolved || !resolver) {
|
|
271
271
|
continue;
|
|
272
272
|
}
|
|
273
273
|
|
|
@@ -277,30 +277,27 @@ export class GraphBuilder {
|
|
|
277
277
|
BuilderInternal.currentDispatcher = this._dispatcher;
|
|
278
278
|
const node = resolver({ id: nodeId });
|
|
279
279
|
BuilderInternal.currentDispatcher = undefined;
|
|
280
|
-
if (node
|
|
280
|
+
if (node) {
|
|
281
|
+
resolved = true;
|
|
281
282
|
this.graph._addNodes([node]);
|
|
282
|
-
if (this._nodeChanged[
|
|
283
|
-
this._nodeChanged[
|
|
283
|
+
if (this._nodeChanged[node.id]) {
|
|
284
|
+
this._nodeChanged[node.id].value = {};
|
|
284
285
|
}
|
|
285
|
-
} else if (node) {
|
|
286
|
-
initialized = node;
|
|
287
286
|
}
|
|
288
287
|
});
|
|
289
288
|
|
|
290
|
-
if (
|
|
289
|
+
if (resolved) {
|
|
290
|
+
this._resolverSubscriptions.get(nodeId)?.();
|
|
291
291
|
this._resolverSubscriptions.set(nodeId, unsubscribe);
|
|
292
292
|
break;
|
|
293
293
|
} else {
|
|
294
294
|
unsubscribe();
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
|
-
|
|
298
|
-
return initialized;
|
|
299
297
|
}
|
|
300
298
|
|
|
301
|
-
private _onInitialNodes(node: Node, nodesRelation: Relation, nodesType?: string) {
|
|
299
|
+
private async _onInitialNodes(node: Node, nodesRelation: Relation, nodesType?: string) {
|
|
302
300
|
this._nodeChanged[node.id] = this._nodeChanged[node.id] ?? signal({});
|
|
303
|
-
let initialized: NodeArg<any>[] | undefined;
|
|
304
301
|
let previous: string[] = [];
|
|
305
302
|
this._connectorSubscriptions.set(
|
|
306
303
|
node.id,
|
|
@@ -332,30 +329,28 @@ export class GraphBuilder {
|
|
|
332
329
|
const removed = previous.filter((id) => !ids.includes(id));
|
|
333
330
|
previous = ids;
|
|
334
331
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
332
|
+
this.graph._removeNodes(removed, true);
|
|
333
|
+
this.graph._addNodes(nodes);
|
|
334
|
+
this.graph._addEdges(
|
|
335
|
+
nodes.map(({ id }) =>
|
|
336
|
+
nodesRelation === 'outbound' ? { source: node.id, target: id } : { source: id, target: node.id },
|
|
337
|
+
),
|
|
338
|
+
);
|
|
339
|
+
this.graph._sortEdges(
|
|
340
|
+
node.id,
|
|
341
|
+
nodesRelation,
|
|
342
|
+
nodes.map(({ id }) => id),
|
|
343
|
+
);
|
|
344
|
+
nodes.forEach((n) => {
|
|
345
|
+
if (this._nodeChanged[n.id]) {
|
|
346
|
+
this._nodeChanged[n.id].value = {};
|
|
347
|
+
}
|
|
348
|
+
});
|
|
352
349
|
}),
|
|
353
350
|
);
|
|
354
|
-
|
|
355
|
-
return initialized;
|
|
356
351
|
}
|
|
357
352
|
|
|
358
|
-
private _onRemoveNode(nodeId: string) {
|
|
353
|
+
private async _onRemoveNode(nodeId: string) {
|
|
359
354
|
this._resolverSubscriptions.get(nodeId)?.();
|
|
360
355
|
this._connectorSubscriptions.get(nodeId)?.();
|
|
361
356
|
this._resolverSubscriptions.delete(nodeId);
|