@dxos/app-graph 0.8.3 → 0.8.4-main.f9ba587
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 +6 -6
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +6 -6
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts +3 -8
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +24 -24
- package/src/stories/EchoGraph.stories.tsx +5 -122
- package/dist/lib/node/index.cjs +0 -816
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
package/dist/lib/node/index.cjs
DELETED
|
@@ -1,816 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var node_exports = {};
|
|
30
|
-
__export(node_exports, {
|
|
31
|
-
ACTION_GROUP_TYPE: () => ACTION_GROUP_TYPE,
|
|
32
|
-
ACTION_TYPE: () => ACTION_TYPE,
|
|
33
|
-
Graph: () => Graph,
|
|
34
|
-
GraphBuilder: () => GraphBuilder,
|
|
35
|
-
ROOT_ID: () => ROOT_ID,
|
|
36
|
-
ROOT_TYPE: () => ROOT_TYPE,
|
|
37
|
-
actionGroupSymbol: () => actionGroupSymbol,
|
|
38
|
-
createExtension: () => createExtension,
|
|
39
|
-
flattenExtensions: () => flattenExtensions,
|
|
40
|
-
getGraph: () => getGraph,
|
|
41
|
-
isAction: () => isAction,
|
|
42
|
-
isActionGroup: () => isActionGroup,
|
|
43
|
-
isActionLike: () => isActionLike,
|
|
44
|
-
isGraphNode: () => isGraphNode,
|
|
45
|
-
rxFromObservable: () => rxFromObservable,
|
|
46
|
-
rxFromSignal: () => rxFromSignal
|
|
47
|
-
});
|
|
48
|
-
module.exports = __toCommonJS(node_exports);
|
|
49
|
-
var import_rx_react = require("@effect-rx/rx-react");
|
|
50
|
-
var import_effect = require("effect");
|
|
51
|
-
var import_async = require("@dxos/async");
|
|
52
|
-
var import_debug = require("@dxos/debug");
|
|
53
|
-
var import_invariant = require("@dxos/invariant");
|
|
54
|
-
var import_log = require("@dxos/log");
|
|
55
|
-
var import_util = require("@dxos/util");
|
|
56
|
-
var import_rx_react2 = require("@effect-rx/rx-react");
|
|
57
|
-
var import_signals_core = require("@preact/signals-core");
|
|
58
|
-
var import_effect2 = require("effect");
|
|
59
|
-
var import_log2 = require("@dxos/log");
|
|
60
|
-
var import_util2 = require("@dxos/util");
|
|
61
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
|
|
62
|
-
var graphSymbol = Symbol("graph");
|
|
63
|
-
var getGraph = (node) => {
|
|
64
|
-
const graph = node[graphSymbol];
|
|
65
|
-
(0, import_invariant.invariant)(graph, "Node is not associated with a graph.", {
|
|
66
|
-
F: __dxlog_file,
|
|
67
|
-
L: 25,
|
|
68
|
-
S: void 0,
|
|
69
|
-
A: [
|
|
70
|
-
"graph",
|
|
71
|
-
"'Node is not associated with a graph.'"
|
|
72
|
-
]
|
|
73
|
-
});
|
|
74
|
-
return graph;
|
|
75
|
-
};
|
|
76
|
-
var ROOT_ID = "root";
|
|
77
|
-
var ROOT_TYPE = "dxos.org/type/GraphRoot";
|
|
78
|
-
var ACTION_TYPE = "dxos.org/type/GraphAction";
|
|
79
|
-
var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
|
|
80
|
-
var Graph = class {
|
|
81
|
-
constructor({ registry, nodes, edges, onExpand, onRemoveNode } = {}) {
|
|
82
|
-
this.onNodeChanged = new import_async.Event();
|
|
83
|
-
this._expanded = import_effect.Record.empty();
|
|
84
|
-
this._initialized = import_effect.Record.empty();
|
|
85
|
-
this._initialEdges = import_effect.Record.empty();
|
|
86
|
-
this._initialNodes = import_effect.Record.fromEntries([
|
|
87
|
-
[
|
|
88
|
-
ROOT_ID,
|
|
89
|
-
this._constructNode({
|
|
90
|
-
id: ROOT_ID,
|
|
91
|
-
type: ROOT_TYPE,
|
|
92
|
-
data: null,
|
|
93
|
-
properties: {}
|
|
94
|
-
})
|
|
95
|
-
]
|
|
96
|
-
]);
|
|
97
|
-
this._node = import_rx_react.Rx.family((id) => {
|
|
98
|
-
const initial = import_effect.Option.flatten(import_effect.Record.get(this._initialNodes, id));
|
|
99
|
-
return import_rx_react.Rx.make(initial).pipe(import_rx_react.Rx.keepAlive, import_rx_react.Rx.withLabel(`graph:node:${id}`));
|
|
100
|
-
});
|
|
101
|
-
this._nodeOrThrow = import_rx_react.Rx.family((id) => {
|
|
102
|
-
return import_rx_react.Rx.make((get) => {
|
|
103
|
-
const node = get(this._node(id));
|
|
104
|
-
(0, import_invariant.invariant)(import_effect.Option.isSome(node), `Node not available: ${id}`, {
|
|
105
|
-
F: __dxlog_file,
|
|
106
|
-
L: 253,
|
|
107
|
-
S: this,
|
|
108
|
-
A: [
|
|
109
|
-
"Option.isSome(node)",
|
|
110
|
-
"`Node not available: ${id}`"
|
|
111
|
-
]
|
|
112
|
-
});
|
|
113
|
-
return node.value;
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
this._edges = import_rx_react.Rx.family((id) => {
|
|
117
|
-
const initial = import_effect.Record.get(this._initialEdges, id).pipe(import_effect.Option.getOrElse(() => ({
|
|
118
|
-
inbound: [],
|
|
119
|
-
outbound: []
|
|
120
|
-
})));
|
|
121
|
-
return import_rx_react.Rx.make(initial).pipe(import_rx_react.Rx.keepAlive, import_rx_react.Rx.withLabel(`graph:edges:${id}`));
|
|
122
|
-
});
|
|
123
|
-
this._connections = import_rx_react.Rx.family((key) => {
|
|
124
|
-
return import_rx_react.Rx.make((get) => {
|
|
125
|
-
const [id, relation] = key.split("$");
|
|
126
|
-
const edges2 = get(this._edges(id));
|
|
127
|
-
return edges2[relation].map((id2) => get(this._node(id2))).filter(import_effect.Option.isSome).map((o) => o.value);
|
|
128
|
-
}).pipe(import_rx_react.Rx.withLabel(`graph:connections:${key}`));
|
|
129
|
-
});
|
|
130
|
-
this._actions = import_rx_react.Rx.family((id) => {
|
|
131
|
-
return import_rx_react.Rx.make((get) => {
|
|
132
|
-
return get(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
|
|
133
|
-
}).pipe(import_rx_react.Rx.withLabel(`graph:actions:${id}`));
|
|
134
|
-
});
|
|
135
|
-
this._json = import_rx_react.Rx.family((id) => {
|
|
136
|
-
return import_rx_react.Rx.make((get) => {
|
|
137
|
-
const toJSON = (node, seen = []) => {
|
|
138
|
-
const nodes2 = get(this.connections(node.id));
|
|
139
|
-
const obj = {
|
|
140
|
-
id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
|
|
141
|
-
type: node.type
|
|
142
|
-
};
|
|
143
|
-
if (node.properties.label) {
|
|
144
|
-
obj.label = node.properties.label;
|
|
145
|
-
}
|
|
146
|
-
if (nodes2.length) {
|
|
147
|
-
obj.nodes = nodes2.map((n) => {
|
|
148
|
-
const nextSeen = [
|
|
149
|
-
...seen,
|
|
150
|
-
node.id
|
|
151
|
-
];
|
|
152
|
-
return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
|
|
153
|
-
}).filter(import_util.isNonNullable);
|
|
154
|
-
}
|
|
155
|
-
return obj;
|
|
156
|
-
};
|
|
157
|
-
const root = get(this.nodeOrThrow(id));
|
|
158
|
-
return toJSON(root);
|
|
159
|
-
}).pipe(import_rx_react.Rx.withLabel(`graph:json:${id}`));
|
|
160
|
-
});
|
|
161
|
-
this._registry = registry ?? import_rx_react.Registry.make();
|
|
162
|
-
this._onExpand = onExpand;
|
|
163
|
-
this._onRemoveNode = onRemoveNode;
|
|
164
|
-
if (nodes) {
|
|
165
|
-
nodes.forEach((node) => {
|
|
166
|
-
import_effect.Record.set(this._initialNodes, node.id, this._constructNode(node));
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
if (edges) {
|
|
170
|
-
Object.entries(edges).forEach(([source, edges2]) => {
|
|
171
|
-
import_effect.Record.set(this._initialEdges, source, edges2);
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
toJSON(id = ROOT_ID) {
|
|
176
|
-
return this._registry.get(this._json(id));
|
|
177
|
-
}
|
|
178
|
-
json(id = ROOT_ID) {
|
|
179
|
-
return this._json(id);
|
|
180
|
-
}
|
|
181
|
-
node(id) {
|
|
182
|
-
return this._node(id);
|
|
183
|
-
}
|
|
184
|
-
nodeOrThrow(id) {
|
|
185
|
-
return this._nodeOrThrow(id);
|
|
186
|
-
}
|
|
187
|
-
connections(id, relation = "outbound") {
|
|
188
|
-
return this._connections(`${id}$${relation}`);
|
|
189
|
-
}
|
|
190
|
-
actions(id) {
|
|
191
|
-
return this._actions(id);
|
|
192
|
-
}
|
|
193
|
-
edges(id) {
|
|
194
|
-
return this._edges(id);
|
|
195
|
-
}
|
|
196
|
-
get root() {
|
|
197
|
-
return this.getNodeOrThrow(ROOT_ID);
|
|
198
|
-
}
|
|
199
|
-
getNode(id) {
|
|
200
|
-
return this._registry.get(this.node(id));
|
|
201
|
-
}
|
|
202
|
-
getNodeOrThrow(id) {
|
|
203
|
-
return this._registry.get(this.nodeOrThrow(id));
|
|
204
|
-
}
|
|
205
|
-
getConnections(id, relation = "outbound") {
|
|
206
|
-
return this._registry.get(this.connections(id, relation));
|
|
207
|
-
}
|
|
208
|
-
getActions(id) {
|
|
209
|
-
return this._registry.get(this.actions(id));
|
|
210
|
-
}
|
|
211
|
-
getEdges(id) {
|
|
212
|
-
return this._registry.get(this.edges(id));
|
|
213
|
-
}
|
|
214
|
-
// TODO(wittjosiah): On initialize to restore state from cache.
|
|
215
|
-
// async initialize(id: string) {
|
|
216
|
-
// const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
|
|
217
|
-
// log('initialize', { id, initialized });
|
|
218
|
-
// if (!initialized) {
|
|
219
|
-
// await this._onInitialize?.(id);
|
|
220
|
-
// Record.set(this._initialized, id, true);
|
|
221
|
-
// }
|
|
222
|
-
// }
|
|
223
|
-
expand(id, relation = "outbound") {
|
|
224
|
-
const key = `${id}$${relation}`;
|
|
225
|
-
const expanded = import_effect.Record.get(this._expanded, key).pipe(import_effect.Option.getOrElse(() => false));
|
|
226
|
-
(0, import_log.log)("expand", {
|
|
227
|
-
key,
|
|
228
|
-
expanded
|
|
229
|
-
}, {
|
|
230
|
-
F: __dxlog_file,
|
|
231
|
-
L: 395,
|
|
232
|
-
S: this,
|
|
233
|
-
C: (f, a) => f(...a)
|
|
234
|
-
});
|
|
235
|
-
if (!expanded) {
|
|
236
|
-
this._onExpand?.(id, relation);
|
|
237
|
-
import_effect.Record.set(this._expanded, key, true);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
addNodes(nodes) {
|
|
241
|
-
import_rx_react.Rx.batch(() => {
|
|
242
|
-
nodes.map((node) => this.addNode(node));
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
addNode({ nodes, edges, ...nodeArg }) {
|
|
246
|
-
const { id, type, data = null, properties = {} } = nodeArg;
|
|
247
|
-
const nodeRx = this._node(id);
|
|
248
|
-
const node = this._registry.get(nodeRx);
|
|
249
|
-
import_effect.Option.match(node, {
|
|
250
|
-
onSome: (node2) => {
|
|
251
|
-
const typeChanged = node2.type !== type;
|
|
252
|
-
const dataChanged = node2.data !== data;
|
|
253
|
-
const propertiesChanged = Object.keys(properties).some((key) => node2.properties[key] !== properties[key]);
|
|
254
|
-
(0, import_log.log)("existing node", {
|
|
255
|
-
id,
|
|
256
|
-
typeChanged,
|
|
257
|
-
dataChanged,
|
|
258
|
-
propertiesChanged
|
|
259
|
-
}, {
|
|
260
|
-
F: __dxlog_file,
|
|
261
|
-
L: 417,
|
|
262
|
-
S: this,
|
|
263
|
-
C: (f, a) => f(...a)
|
|
264
|
-
});
|
|
265
|
-
if (typeChanged || dataChanged || propertiesChanged) {
|
|
266
|
-
(0, import_log.log)("updating node", {
|
|
267
|
-
id,
|
|
268
|
-
type,
|
|
269
|
-
data,
|
|
270
|
-
properties
|
|
271
|
-
}, {
|
|
272
|
-
F: __dxlog_file,
|
|
273
|
-
L: 419,
|
|
274
|
-
S: this,
|
|
275
|
-
C: (f, a) => f(...a)
|
|
276
|
-
});
|
|
277
|
-
const newNode = import_effect.Option.some({
|
|
278
|
-
...node2,
|
|
279
|
-
type,
|
|
280
|
-
data,
|
|
281
|
-
properties: {
|
|
282
|
-
...node2.properties,
|
|
283
|
-
...properties
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
this._registry.set(nodeRx, newNode);
|
|
287
|
-
this.onNodeChanged.emit({
|
|
288
|
-
id,
|
|
289
|
-
node: newNode
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
onNone: () => {
|
|
294
|
-
(0, import_log.log)("new node", {
|
|
295
|
-
id,
|
|
296
|
-
type,
|
|
297
|
-
data,
|
|
298
|
-
properties
|
|
299
|
-
}, {
|
|
300
|
-
F: __dxlog_file,
|
|
301
|
-
L: 426,
|
|
302
|
-
S: this,
|
|
303
|
-
C: (f, a) => f(...a)
|
|
304
|
-
});
|
|
305
|
-
const newNode = this._constructNode({
|
|
306
|
-
id,
|
|
307
|
-
type,
|
|
308
|
-
data,
|
|
309
|
-
properties
|
|
310
|
-
});
|
|
311
|
-
this._registry.set(nodeRx, newNode);
|
|
312
|
-
this.onNodeChanged.emit({
|
|
313
|
-
id,
|
|
314
|
-
node: newNode
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
if (nodes) {
|
|
319
|
-
this.addNodes(nodes);
|
|
320
|
-
const _edges = nodes.map((node2) => ({
|
|
321
|
-
source: id,
|
|
322
|
-
target: node2.id
|
|
323
|
-
}));
|
|
324
|
-
this.addEdges(_edges);
|
|
325
|
-
}
|
|
326
|
-
if (edges) {
|
|
327
|
-
(0, import_debug.todo)();
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
removeNodes(ids, edges = false) {
|
|
331
|
-
import_rx_react.Rx.batch(() => {
|
|
332
|
-
ids.map((id) => this.removeNode(id, edges));
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
removeNode(id, edges = false) {
|
|
336
|
-
const nodeRx = this._node(id);
|
|
337
|
-
this._registry.set(nodeRx, import_effect.Option.none());
|
|
338
|
-
this.onNodeChanged.emit({
|
|
339
|
-
id,
|
|
340
|
-
node: import_effect.Option.none()
|
|
341
|
-
});
|
|
342
|
-
if (edges) {
|
|
343
|
-
const { inbound, outbound } = this._registry.get(this._edges(id));
|
|
344
|
-
const edges2 = [
|
|
345
|
-
...inbound.map((source) => ({
|
|
346
|
-
source,
|
|
347
|
-
target: id
|
|
348
|
-
})),
|
|
349
|
-
...outbound.map((target) => ({
|
|
350
|
-
source: id,
|
|
351
|
-
target
|
|
352
|
-
}))
|
|
353
|
-
];
|
|
354
|
-
this.removeEdges(edges2);
|
|
355
|
-
}
|
|
356
|
-
this._onRemoveNode?.(id);
|
|
357
|
-
}
|
|
358
|
-
addEdges(edges) {
|
|
359
|
-
import_rx_react.Rx.batch(() => {
|
|
360
|
-
edges.map((edge) => this.addEdge(edge));
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
addEdge(edgeArg) {
|
|
364
|
-
const sourceRx = this._edges(edgeArg.source);
|
|
365
|
-
const source = this._registry.get(sourceRx);
|
|
366
|
-
if (!source.outbound.includes(edgeArg.target)) {
|
|
367
|
-
(0, import_log.log)("add outbound edge", {
|
|
368
|
-
source: edgeArg.source,
|
|
369
|
-
target: edgeArg.target
|
|
370
|
-
}, {
|
|
371
|
-
F: __dxlog_file,
|
|
372
|
-
L: 481,
|
|
373
|
-
S: this,
|
|
374
|
-
C: (f, a) => f(...a)
|
|
375
|
-
});
|
|
376
|
-
this._registry.set(sourceRx, {
|
|
377
|
-
inbound: source.inbound,
|
|
378
|
-
outbound: [
|
|
379
|
-
...source.outbound,
|
|
380
|
-
edgeArg.target
|
|
381
|
-
]
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
const targetRx = this._edges(edgeArg.target);
|
|
385
|
-
const target = this._registry.get(targetRx);
|
|
386
|
-
if (!target.inbound.includes(edgeArg.source)) {
|
|
387
|
-
(0, import_log.log)("add inbound edge", {
|
|
388
|
-
source: edgeArg.source,
|
|
389
|
-
target: edgeArg.target
|
|
390
|
-
}, {
|
|
391
|
-
F: __dxlog_file,
|
|
392
|
-
L: 488,
|
|
393
|
-
S: this,
|
|
394
|
-
C: (f, a) => f(...a)
|
|
395
|
-
});
|
|
396
|
-
this._registry.set(targetRx, {
|
|
397
|
-
inbound: [
|
|
398
|
-
...target.inbound,
|
|
399
|
-
edgeArg.source
|
|
400
|
-
],
|
|
401
|
-
outbound: target.outbound
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
removeEdges(edges, removeOrphans = false) {
|
|
406
|
-
import_rx_react.Rx.batch(() => {
|
|
407
|
-
edges.map((edge) => this.removeEdge(edge, removeOrphans));
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
removeEdge(edgeArg, removeOrphans = false) {
|
|
411
|
-
const sourceRx = this._edges(edgeArg.source);
|
|
412
|
-
const source = this._registry.get(sourceRx);
|
|
413
|
-
if (source.outbound.includes(edgeArg.target)) {
|
|
414
|
-
this._registry.set(sourceRx, {
|
|
415
|
-
inbound: source.inbound,
|
|
416
|
-
outbound: source.outbound.filter((id) => id !== edgeArg.target)
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
const targetRx = this._edges(edgeArg.target);
|
|
420
|
-
const target = this._registry.get(targetRx);
|
|
421
|
-
if (target.inbound.includes(edgeArg.source)) {
|
|
422
|
-
this._registry.set(targetRx, {
|
|
423
|
-
inbound: target.inbound.filter((id) => id !== edgeArg.source),
|
|
424
|
-
outbound: target.outbound
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
if (removeOrphans) {
|
|
428
|
-
const source2 = this._registry.get(sourceRx);
|
|
429
|
-
const target2 = this._registry.get(targetRx);
|
|
430
|
-
if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
|
|
431
|
-
this.removeNodes([
|
|
432
|
-
edgeArg.source
|
|
433
|
-
]);
|
|
434
|
-
}
|
|
435
|
-
if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== ROOT_ID) {
|
|
436
|
-
this.removeNodes([
|
|
437
|
-
edgeArg.target
|
|
438
|
-
]);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
sortEdges(id, relation, order) {
|
|
443
|
-
const edgesRx = this._edges(id);
|
|
444
|
-
const edges = this._registry.get(edgesRx);
|
|
445
|
-
const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
|
|
446
|
-
const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
|
|
447
|
-
edges[relation].splice(0, edges[relation].length, ...[
|
|
448
|
-
...sorted,
|
|
449
|
-
...unsorted
|
|
450
|
-
]);
|
|
451
|
-
this._registry.set(edgesRx, edges);
|
|
452
|
-
}
|
|
453
|
-
traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
|
|
454
|
-
if (path.includes(source)) {
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
const node = this.getNodeOrThrow(source);
|
|
458
|
-
const shouldContinue = visitor(node, [
|
|
459
|
-
...path,
|
|
460
|
-
source
|
|
461
|
-
]);
|
|
462
|
-
if (shouldContinue === false) {
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
Object.values(this.getConnections(source, relation)).forEach((child) => this.traverse({
|
|
466
|
-
source: child.id,
|
|
467
|
-
relation,
|
|
468
|
-
visitor
|
|
469
|
-
}, [
|
|
470
|
-
...path,
|
|
471
|
-
source
|
|
472
|
-
]));
|
|
473
|
-
}
|
|
474
|
-
getPath({ source = "root", target }) {
|
|
475
|
-
return (0, import_effect.pipe)(this.getNode(source), import_effect.Option.flatMap((node) => {
|
|
476
|
-
let found = import_effect.Option.none();
|
|
477
|
-
this.traverse({
|
|
478
|
-
source: node.id,
|
|
479
|
-
visitor: (node2, path) => {
|
|
480
|
-
if (import_effect.Option.isSome(found)) {
|
|
481
|
-
return false;
|
|
482
|
-
}
|
|
483
|
-
if (node2.id === target) {
|
|
484
|
-
found = import_effect.Option.some(path);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
});
|
|
488
|
-
return found;
|
|
489
|
-
}));
|
|
490
|
-
}
|
|
491
|
-
async waitForPath(params, { timeout = 5e3, interval = 500 } = {}) {
|
|
492
|
-
const path = this.getPath(params);
|
|
493
|
-
if (import_effect.Option.isSome(path)) {
|
|
494
|
-
return path.value;
|
|
495
|
-
}
|
|
496
|
-
const trigger = new import_async.Trigger();
|
|
497
|
-
const i = setInterval(() => {
|
|
498
|
-
const path2 = this.getPath(params);
|
|
499
|
-
if (import_effect.Option.isSome(path2)) {
|
|
500
|
-
trigger.wake(path2.value);
|
|
501
|
-
}
|
|
502
|
-
}, interval);
|
|
503
|
-
return trigger.wait({
|
|
504
|
-
timeout
|
|
505
|
-
}).finally(() => clearInterval(i));
|
|
506
|
-
}
|
|
507
|
-
/** @internal */
|
|
508
|
-
_constructNode(node) {
|
|
509
|
-
return import_effect.Option.some({
|
|
510
|
-
[graphSymbol]: this,
|
|
511
|
-
data: null,
|
|
512
|
-
properties: {},
|
|
513
|
-
...node
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
};
|
|
517
|
-
var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
|
|
518
|
-
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" : false;
|
|
519
|
-
var actionGroupSymbol = Symbol("ActionGroup");
|
|
520
|
-
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol : false;
|
|
521
|
-
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
522
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
|
|
523
|
-
var createExtension = (extension) => {
|
|
524
|
-
const { id, position = "static", relation = "outbound", connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
|
|
525
|
-
const getId = (key) => `${id}/${key}`;
|
|
526
|
-
const connector = _connector && import_rx_react2.Rx.family((node) => _connector(node).pipe(import_rx_react2.Rx.withLabel(`graph-builder:_connector:${id}`)));
|
|
527
|
-
const actionGroups = _actionGroups && import_rx_react2.Rx.family((node) => _actionGroups(node).pipe(import_rx_react2.Rx.withLabel(`graph-builder:_actionGroups:${id}`)));
|
|
528
|
-
const actions = _actions && import_rx_react2.Rx.family((node) => _actions(node).pipe(import_rx_react2.Rx.withLabel(`graph-builder:_actions:${id}`)));
|
|
529
|
-
return [
|
|
530
|
-
// resolver ? { id: getId('resolver'), position, resolver } : undefined,
|
|
531
|
-
connector ? {
|
|
532
|
-
id: getId("connector"),
|
|
533
|
-
position,
|
|
534
|
-
relation,
|
|
535
|
-
connector: import_rx_react2.Rx.family((node) => import_rx_react2.Rx.make((get) => {
|
|
536
|
-
try {
|
|
537
|
-
return get(connector(node));
|
|
538
|
-
} catch {
|
|
539
|
-
import_log2.log.warn("Error in connector", {
|
|
540
|
-
id: getId("connector"),
|
|
541
|
-
node
|
|
542
|
-
}, {
|
|
543
|
-
F: __dxlog_file2,
|
|
544
|
-
L: 101,
|
|
545
|
-
S: void 0,
|
|
546
|
-
C: (f, a) => f(...a)
|
|
547
|
-
});
|
|
548
|
-
return [];
|
|
549
|
-
}
|
|
550
|
-
}).pipe(import_rx_react2.Rx.withLabel(`graph-builder:connector:${id}`)))
|
|
551
|
-
} : void 0,
|
|
552
|
-
actionGroups ? {
|
|
553
|
-
id: getId("actionGroups"),
|
|
554
|
-
position,
|
|
555
|
-
relation: "outbound",
|
|
556
|
-
connector: import_rx_react2.Rx.family((node) => import_rx_react2.Rx.make((get) => {
|
|
557
|
-
try {
|
|
558
|
-
return get(actionGroups(node)).map((arg) => ({
|
|
559
|
-
...arg,
|
|
560
|
-
data: actionGroupSymbol,
|
|
561
|
-
type: ACTION_GROUP_TYPE
|
|
562
|
-
}));
|
|
563
|
-
} catch {
|
|
564
|
-
import_log2.log.warn("Error in actionGroups", {
|
|
565
|
-
id: getId("actionGroups"),
|
|
566
|
-
node
|
|
567
|
-
}, {
|
|
568
|
-
F: __dxlog_file2,
|
|
569
|
-
L: 122,
|
|
570
|
-
S: void 0,
|
|
571
|
-
C: (f, a) => f(...a)
|
|
572
|
-
});
|
|
573
|
-
return [];
|
|
574
|
-
}
|
|
575
|
-
}).pipe(import_rx_react2.Rx.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
576
|
-
} : void 0,
|
|
577
|
-
actions ? {
|
|
578
|
-
id: getId("actions"),
|
|
579
|
-
position,
|
|
580
|
-
relation: "outbound",
|
|
581
|
-
connector: import_rx_react2.Rx.family((node) => import_rx_react2.Rx.make((get) => {
|
|
582
|
-
try {
|
|
583
|
-
return get(actions(node)).map((arg) => ({
|
|
584
|
-
...arg,
|
|
585
|
-
type: ACTION_TYPE
|
|
586
|
-
}));
|
|
587
|
-
} catch {
|
|
588
|
-
import_log2.log.warn("Error in actions", {
|
|
589
|
-
id: getId("actions"),
|
|
590
|
-
node
|
|
591
|
-
}, {
|
|
592
|
-
F: __dxlog_file2,
|
|
593
|
-
L: 139,
|
|
594
|
-
S: void 0,
|
|
595
|
-
C: (f, a) => f(...a)
|
|
596
|
-
});
|
|
597
|
-
return [];
|
|
598
|
-
}
|
|
599
|
-
}).pipe(import_rx_react2.Rx.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
600
|
-
} : void 0
|
|
601
|
-
].filter(import_util2.isNonNullable);
|
|
602
|
-
};
|
|
603
|
-
var flattenExtensions = (extension, acc = []) => {
|
|
604
|
-
if (import_effect2.Array.isArray(extension)) {
|
|
605
|
-
return [
|
|
606
|
-
...acc,
|
|
607
|
-
...extension.flatMap((ext) => flattenExtensions(ext, acc))
|
|
608
|
-
];
|
|
609
|
-
} else {
|
|
610
|
-
return [
|
|
611
|
-
...acc,
|
|
612
|
-
extension
|
|
613
|
-
];
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
var GraphBuilder = class _GraphBuilder {
|
|
617
|
-
constructor({ registry, ...params } = {}) {
|
|
618
|
-
this._connectorSubscriptions = /* @__PURE__ */ new Map();
|
|
619
|
-
this._extensions = import_rx_react2.Rx.make(import_effect2.Record.empty()).pipe(import_rx_react2.Rx.keepAlive, import_rx_react2.Rx.withLabel("graph-builder:extensions"));
|
|
620
|
-
this._connectors = import_rx_react2.Rx.family((key) => {
|
|
621
|
-
return import_rx_react2.Rx.make((get) => {
|
|
622
|
-
const [id, relation] = key.split("+");
|
|
623
|
-
const node = this._graph.node(id);
|
|
624
|
-
return (0, import_effect2.pipe)(
|
|
625
|
-
get(this._extensions),
|
|
626
|
-
import_effect2.Record.values,
|
|
627
|
-
// TODO(wittjosiah): Sort on write rather than read.
|
|
628
|
-
import_effect2.Array.sortBy(import_util2.byPosition),
|
|
629
|
-
import_effect2.Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
630
|
-
import_effect2.Array.map(({ connector }) => connector?.(node)),
|
|
631
|
-
import_effect2.Array.filter(import_util2.isNonNullable),
|
|
632
|
-
import_effect2.Array.flatMap((result) => get(result))
|
|
633
|
-
);
|
|
634
|
-
}).pipe(import_rx_react2.Rx.withLabel(`graph-builder:connectors:${key}`));
|
|
635
|
-
});
|
|
636
|
-
this._registry = registry ?? import_rx_react2.Registry.make();
|
|
637
|
-
this._graph = new Graph({
|
|
638
|
-
...params,
|
|
639
|
-
registry: this._registry,
|
|
640
|
-
onExpand: (id, relation) => this._onExpand(id, relation),
|
|
641
|
-
// onInitialize: (id) => this._onInitialize(id),
|
|
642
|
-
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
static from(pickle, registry) {
|
|
646
|
-
if (!pickle) {
|
|
647
|
-
return new _GraphBuilder({
|
|
648
|
-
registry
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
const { nodes, edges } = JSON.parse(pickle);
|
|
652
|
-
return new _GraphBuilder({
|
|
653
|
-
nodes,
|
|
654
|
-
edges,
|
|
655
|
-
registry
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
get graph() {
|
|
659
|
-
return this._graph;
|
|
660
|
-
}
|
|
661
|
-
get extensions() {
|
|
662
|
-
return this._extensions;
|
|
663
|
-
}
|
|
664
|
-
addExtension(extensions) {
|
|
665
|
-
flattenExtensions(extensions).forEach((extension) => {
|
|
666
|
-
const extensions2 = this._registry.get(this._extensions);
|
|
667
|
-
this._registry.set(this._extensions, import_effect2.Record.set(extensions2, extension.id, extension));
|
|
668
|
-
});
|
|
669
|
-
return this;
|
|
670
|
-
}
|
|
671
|
-
removeExtension(id) {
|
|
672
|
-
const extensions = this._registry.get(this._extensions);
|
|
673
|
-
this._registry.set(this._extensions, import_effect2.Record.remove(extensions, id));
|
|
674
|
-
return this;
|
|
675
|
-
}
|
|
676
|
-
async explore({ registry = import_rx_react2.Registry.make(), source = ROOT_ID, relation = "outbound", visitor }, path = []) {
|
|
677
|
-
if (path.includes(source)) {
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
if (!(0, import_util2.isNode)()) {
|
|
681
|
-
const { yieldOrContinue } = await import("main-thread-scheduling");
|
|
682
|
-
await yieldOrContinue("idle");
|
|
683
|
-
}
|
|
684
|
-
const node = registry.get(this._graph.nodeOrThrow(source));
|
|
685
|
-
const shouldContinue = await visitor(node, [
|
|
686
|
-
...path,
|
|
687
|
-
node.id
|
|
688
|
-
]);
|
|
689
|
-
if (shouldContinue === false) {
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
const nodes = Object.values(this._registry.get(this._extensions)).filter((extension) => relation === (extension.relation ?? "outbound")).map((extension) => extension.connector).filter(import_util2.isNonNullable).flatMap((connector) => registry.get(connector(this._graph.node(source))));
|
|
693
|
-
await Promise.all(nodes.map((nodeArg) => {
|
|
694
|
-
registry.set(this._graph._node(nodeArg.id), this._graph._constructNode(nodeArg));
|
|
695
|
-
return this.explore({
|
|
696
|
-
registry,
|
|
697
|
-
source: nodeArg.id,
|
|
698
|
-
relation,
|
|
699
|
-
visitor
|
|
700
|
-
}, [
|
|
701
|
-
...path,
|
|
702
|
-
node.id
|
|
703
|
-
]);
|
|
704
|
-
}));
|
|
705
|
-
if (registry !== this._registry) {
|
|
706
|
-
registry.reset();
|
|
707
|
-
registry.dispose();
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
destroy() {
|
|
711
|
-
this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
712
|
-
this._connectorSubscriptions.clear();
|
|
713
|
-
}
|
|
714
|
-
_onExpand(id, relation) {
|
|
715
|
-
(0, import_log2.log)("onExpand", {
|
|
716
|
-
id,
|
|
717
|
-
relation,
|
|
718
|
-
registry: (0, import_util2.getDebugName)(this._registry)
|
|
719
|
-
}, {
|
|
720
|
-
F: __dxlog_file2,
|
|
721
|
-
L: 301,
|
|
722
|
-
S: this,
|
|
723
|
-
C: (f, a) => f(...a)
|
|
724
|
-
});
|
|
725
|
-
const connectors = this._connectors(`${id}+${relation}`);
|
|
726
|
-
let previous = [];
|
|
727
|
-
const cancel = this._registry.subscribe(connectors, (nodes) => {
|
|
728
|
-
const ids = nodes.map((n) => n.id);
|
|
729
|
-
const removed = previous.filter((id2) => !ids.includes(id2));
|
|
730
|
-
previous = ids;
|
|
731
|
-
(0, import_log2.log)("update", {
|
|
732
|
-
id,
|
|
733
|
-
relation,
|
|
734
|
-
ids,
|
|
735
|
-
removed
|
|
736
|
-
}, {
|
|
737
|
-
F: __dxlog_file2,
|
|
738
|
-
L: 312,
|
|
739
|
-
S: this,
|
|
740
|
-
C: (f, a) => f(...a)
|
|
741
|
-
});
|
|
742
|
-
const update = () => {
|
|
743
|
-
import_rx_react2.Rx.batch(() => {
|
|
744
|
-
this._graph.removeEdges(removed.map((target) => ({
|
|
745
|
-
source: id,
|
|
746
|
-
target
|
|
747
|
-
})), true);
|
|
748
|
-
this._graph.addNodes(nodes);
|
|
749
|
-
this._graph.addEdges(nodes.map((node) => relation === "outbound" ? {
|
|
750
|
-
source: id,
|
|
751
|
-
target: node.id
|
|
752
|
-
} : {
|
|
753
|
-
source: node.id,
|
|
754
|
-
target: id
|
|
755
|
-
}));
|
|
756
|
-
this._graph.sortEdges(id, relation, nodes.map(({ id: id2 }) => id2));
|
|
757
|
-
});
|
|
758
|
-
};
|
|
759
|
-
if (typeof requestAnimationFrame === "function") {
|
|
760
|
-
requestAnimationFrame(update);
|
|
761
|
-
} else {
|
|
762
|
-
update();
|
|
763
|
-
}
|
|
764
|
-
}, {
|
|
765
|
-
immediate: true
|
|
766
|
-
});
|
|
767
|
-
this._connectorSubscriptions.set(id, cancel);
|
|
768
|
-
}
|
|
769
|
-
// TODO(wittjosiah): On initialize to restore state from cache.
|
|
770
|
-
// private async _onInitialize(id: string) {
|
|
771
|
-
// log('onInitialize', { id });
|
|
772
|
-
// }
|
|
773
|
-
_onRemoveNode(id) {
|
|
774
|
-
this._connectorSubscriptions.get(id)?.();
|
|
775
|
-
this._connectorSubscriptions.delete(id);
|
|
776
|
-
}
|
|
777
|
-
};
|
|
778
|
-
var rxFromSignal = (cb) => {
|
|
779
|
-
return import_rx_react2.Rx.make((get) => {
|
|
780
|
-
const dispose = (0, import_signals_core.effect)(() => {
|
|
781
|
-
get.setSelf(cb());
|
|
782
|
-
});
|
|
783
|
-
get.addFinalizer(() => dispose());
|
|
784
|
-
return cb();
|
|
785
|
-
});
|
|
786
|
-
};
|
|
787
|
-
var observableFamily = import_rx_react2.Rx.family((observable) => {
|
|
788
|
-
return import_rx_react2.Rx.make((get) => {
|
|
789
|
-
const subscription = observable.subscribe((value) => get.setSelf(value));
|
|
790
|
-
get.addFinalizer(() => subscription.unsubscribe());
|
|
791
|
-
return observable.get();
|
|
792
|
-
});
|
|
793
|
-
});
|
|
794
|
-
var rxFromObservable = (observable) => {
|
|
795
|
-
return observableFamily(observable);
|
|
796
|
-
};
|
|
797
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
798
|
-
0 && (module.exports = {
|
|
799
|
-
ACTION_GROUP_TYPE,
|
|
800
|
-
ACTION_TYPE,
|
|
801
|
-
Graph,
|
|
802
|
-
GraphBuilder,
|
|
803
|
-
ROOT_ID,
|
|
804
|
-
ROOT_TYPE,
|
|
805
|
-
actionGroupSymbol,
|
|
806
|
-
createExtension,
|
|
807
|
-
flattenExtensions,
|
|
808
|
-
getGraph,
|
|
809
|
-
isAction,
|
|
810
|
-
isActionGroup,
|
|
811
|
-
isActionLike,
|
|
812
|
-
isGraphNode,
|
|
813
|
-
rxFromObservable,
|
|
814
|
-
rxFromSignal
|
|
815
|
-
});
|
|
816
|
-
//# sourceMappingURL=index.cjs.map
|