@dxos/app-graph 0.4.7-main.d28a540 → 0.4.7-main.e015b9e
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 +229 -289
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing.mjs +98 -0
- package/dist/lib/browser/testing.mjs.map +7 -0
- package/dist/lib/node/index.cjs +239 -282
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing.cjs +122 -0
- package/dist/lib/node/testing.cjs.map +7 -0
- package/dist/types/src/action.d.ts +68 -0
- package/dist/types/src/action.d.ts.map +1 -0
- package/dist/types/src/graph-builder.d.ts +16 -8
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +14 -71
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/node.d.ts +47 -57
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/src/testing.d.ts +52 -0
- package/dist/types/src/testing.d.ts.map +1 -0
- package/package.json +29 -10
- package/src/action.ts +92 -0
- package/src/graph-builder.ts +206 -18
- package/src/graph.test.ts +146 -242
- package/src/graph.ts +48 -241
- package/src/index.ts +1 -1
- package/src/node.ts +66 -78
- package/src/stories/EchoGraph.stories.tsx +27 -59
- package/src/testing.ts +152 -0
- package/dist/types/src/helpers.d.ts +0 -14
- package/dist/types/src/helpers.d.ts.map +0 -1
- package/src/helpers.ts +0 -27
|
@@ -1,352 +1,292 @@
|
|
|
1
1
|
// packages/sdk/app-graph/src/graph.ts
|
|
2
|
-
import { untracked } from "@preact/signals-core";
|
|
3
2
|
import { deepSignal } from "deepsignal/react";
|
|
3
|
+
import get from "lodash.get";
|
|
4
4
|
import { invariant } from "@dxos/invariant";
|
|
5
|
-
import { nonNullable } from "@dxos/util";
|
|
6
|
-
|
|
7
|
-
// packages/sdk/app-graph/src/node.ts
|
|
8
|
-
var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
|
|
9
|
-
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" : false;
|
|
10
|
-
var actionGroupSymbol = Symbol("ActionGroup");
|
|
11
|
-
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol : false;
|
|
12
|
-
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
13
|
-
|
|
14
|
-
// packages/sdk/app-graph/src/graph.ts
|
|
15
5
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
|
|
16
|
-
var ROOT_ID = "root";
|
|
17
6
|
var Graph = class {
|
|
18
|
-
constructor() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// Explicit type required because TS says this is not portable.
|
|
34
|
-
this._edges = deepSignal({});
|
|
35
|
-
this._constructNode = (nodeBase) => {
|
|
36
|
-
const node = {
|
|
37
|
-
...nodeBase,
|
|
38
|
-
edges: ({ direction = "outbound" } = {}) => {
|
|
39
|
-
return this._edges[this.getEdgeKey(node.id, direction)];
|
|
40
|
-
},
|
|
41
|
-
nodes: ({ direction, filter } = {}) => {
|
|
42
|
-
const nodes = this._getNodes({
|
|
43
|
-
id: node.id,
|
|
44
|
-
direction
|
|
45
|
-
}).filter((n) => !isActionLike(n));
|
|
46
|
-
return filter ? nodes.filter((n) => filter(n, node)) : nodes;
|
|
47
|
-
},
|
|
48
|
-
node: (id) => {
|
|
49
|
-
return this._getNodes({
|
|
50
|
-
id
|
|
51
|
-
}).find((node2) => node2.id === id);
|
|
52
|
-
},
|
|
53
|
-
actions: () => {
|
|
54
|
-
return this._getNodes({
|
|
55
|
-
id: node.id
|
|
56
|
-
}).filter(isActionLike);
|
|
57
|
-
}
|
|
7
|
+
constructor(_root) {
|
|
8
|
+
this._root = _root;
|
|
9
|
+
this._index = deepSignal({});
|
|
10
|
+
}
|
|
11
|
+
toJSON() {
|
|
12
|
+
const toLabel = (label) => Array.isArray(label) ? `${label[1].ns}[${label[0]}]` : label;
|
|
13
|
+
const toJSON = (node) => {
|
|
14
|
+
return {
|
|
15
|
+
id: node.id.slice(0, 16),
|
|
16
|
+
label: toLabel(node.label),
|
|
17
|
+
children: node.children.length ? node.children.map((node2) => toJSON(node2)) : void 0,
|
|
18
|
+
actions: node.actions.length ? node.actions.map(({ id, label }) => ({
|
|
19
|
+
id,
|
|
20
|
+
label: toLabel(label)
|
|
21
|
+
})) : void 0
|
|
58
22
|
};
|
|
59
|
-
return node;
|
|
60
23
|
};
|
|
24
|
+
return toJSON(this._root);
|
|
61
25
|
}
|
|
62
26
|
/**
|
|
63
|
-
*
|
|
27
|
+
* The root node of the graph which is the entry point for all knowledge.
|
|
64
28
|
*/
|
|
65
29
|
get root() {
|
|
66
|
-
return this.
|
|
30
|
+
return this._root;
|
|
67
31
|
}
|
|
68
32
|
/**
|
|
69
|
-
*
|
|
33
|
+
* Get the path through the graph from the root to the node with the given id.
|
|
70
34
|
*/
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
if (nodes.length) {
|
|
81
|
-
obj.nodes = nodes.map((node2) => toJSON(node2));
|
|
82
|
-
}
|
|
83
|
-
return obj;
|
|
84
|
-
};
|
|
85
|
-
const root = this.findNode(id);
|
|
86
|
-
invariant(root, `Node not found: ${id}`, {
|
|
35
|
+
getPath(id) {
|
|
36
|
+
return this._index[id];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
_setPath(id, path) {
|
|
42
|
+
invariant(id && path, "Invalid path.", {
|
|
87
43
|
F: __dxlog_file,
|
|
88
|
-
L:
|
|
44
|
+
L: 82,
|
|
89
45
|
S: this,
|
|
90
46
|
A: [
|
|
91
|
-
"
|
|
92
|
-
"
|
|
47
|
+
"id && path",
|
|
48
|
+
"'Invalid path.'"
|
|
93
49
|
]
|
|
94
50
|
});
|
|
95
|
-
|
|
51
|
+
this._index[id] = path;
|
|
96
52
|
}
|
|
97
53
|
/**
|
|
98
54
|
* Find the node with the given id in the graph.
|
|
99
55
|
*/
|
|
100
56
|
findNode(id) {
|
|
101
|
-
const
|
|
102
|
-
if (!
|
|
57
|
+
const path = this.getPath(id);
|
|
58
|
+
if (!path) {
|
|
103
59
|
return void 0;
|
|
104
60
|
}
|
|
105
|
-
return this.
|
|
106
|
-
}
|
|
107
|
-
_getNodes({ id, direction = "outbound" }) {
|
|
108
|
-
const edges = this._edges[this.getEdgeKey(id, direction)];
|
|
109
|
-
if (!edges) {
|
|
110
|
-
return [];
|
|
111
|
-
}
|
|
112
|
-
return edges.map((id2) => this.findNode(id2)).filter(nonNullable);
|
|
113
|
-
}
|
|
114
|
-
getEdgeKey(id, direction) {
|
|
115
|
-
return `${id}-${direction}`;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Add nodes to the graph.
|
|
119
|
-
*/
|
|
120
|
-
addNodes(...nodes) {
|
|
121
|
-
return nodes.map((node) => this._addNode(node));
|
|
122
|
-
}
|
|
123
|
-
_addNode({ nodes, edges, ..._node }) {
|
|
124
|
-
return untracked(() => {
|
|
125
|
-
const node = {
|
|
126
|
-
data: null,
|
|
127
|
-
properties: {},
|
|
128
|
-
..._node
|
|
129
|
-
};
|
|
130
|
-
this._nodes[node.id] = node;
|
|
131
|
-
if (nodes) {
|
|
132
|
-
nodes.forEach((subNode) => {
|
|
133
|
-
this._addNode(subNode);
|
|
134
|
-
this.addEdge({
|
|
135
|
-
source: node.id,
|
|
136
|
-
target: subNode.id
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
if (edges) {
|
|
141
|
-
edges.forEach(([id, direction]) => direction === "outbound" ? this.addEdge({
|
|
142
|
-
source: node.id,
|
|
143
|
-
target: id
|
|
144
|
-
}) : this.addEdge({
|
|
145
|
-
source: id,
|
|
146
|
-
target: node.id
|
|
147
|
-
}));
|
|
148
|
-
}
|
|
149
|
-
return this._constructNode(node);
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Remove nodes from the graph.
|
|
154
|
-
*
|
|
155
|
-
* @param id The id of the node to remove.
|
|
156
|
-
* @param edges Whether to remove edges connected to the node from the graph as well.
|
|
157
|
-
*/
|
|
158
|
-
removeNode(id, edges = false) {
|
|
159
|
-
untracked(() => {
|
|
160
|
-
const node = this.findNode(id);
|
|
161
|
-
if (!node) {
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (edges) {
|
|
165
|
-
delete this._edges[this.getEdgeKey(id, "outbound")];
|
|
166
|
-
delete this._edges[this.getEdgeKey(id, "inbound")];
|
|
167
|
-
this._getNodes({
|
|
168
|
-
id
|
|
169
|
-
}).forEach((node2) => this.removeEdge({
|
|
170
|
-
source: id,
|
|
171
|
-
target: node2.id
|
|
172
|
-
}));
|
|
173
|
-
this._getNodes({
|
|
174
|
-
id,
|
|
175
|
-
direction: "inbound"
|
|
176
|
-
}).forEach((node2) => this.removeEdge({
|
|
177
|
-
source: node2.id,
|
|
178
|
-
target: id
|
|
179
|
-
}));
|
|
180
|
-
}
|
|
181
|
-
delete this._nodes[id];
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Add an edge to the graph.
|
|
186
|
-
*/
|
|
187
|
-
addEdge({ source, target }) {
|
|
188
|
-
untracked(() => {
|
|
189
|
-
const outbound = this._edges[this.getEdgeKey(source, "outbound")];
|
|
190
|
-
if (!outbound) {
|
|
191
|
-
this._edges[this.getEdgeKey(source, "outbound")] = [
|
|
192
|
-
target
|
|
193
|
-
];
|
|
194
|
-
} else if (!outbound.includes(target)) {
|
|
195
|
-
outbound.push(target);
|
|
196
|
-
}
|
|
197
|
-
const inbound = this._edges[this.getEdgeKey(target, "inbound")];
|
|
198
|
-
if (!inbound) {
|
|
199
|
-
this._edges[this.getEdgeKey(target, "inbound")] = [
|
|
200
|
-
source
|
|
201
|
-
];
|
|
202
|
-
} else if (!inbound.includes(source)) {
|
|
203
|
-
inbound.push(source);
|
|
204
|
-
}
|
|
205
|
-
});
|
|
61
|
+
return path.length > 0 ? get(this._root, path) : this._root;
|
|
206
62
|
}
|
|
207
63
|
/**
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* Edges not included in the sorted list are appended to the end of the list.
|
|
211
|
-
*
|
|
212
|
-
* @param nodeId The id of the node to sort edges for.
|
|
213
|
-
* @param direction The direction of the edges from the node to sort.
|
|
214
|
-
* @param edges The ordered list of edges.
|
|
64
|
+
* Recursive breadth-first traversal.
|
|
215
65
|
*/
|
|
216
|
-
|
|
217
|
-
untracked(() => {
|
|
218
|
-
const current = this._edges[this.getEdgeKey(nodeId, direction)];
|
|
219
|
-
if (current) {
|
|
220
|
-
const unsorted = current.filter((id) => !edges.includes(id)) ?? [];
|
|
221
|
-
const sorted = edges.filter((id) => current.includes(id)) ?? [];
|
|
222
|
-
current.splice(0, current.length, ...[
|
|
223
|
-
...sorted,
|
|
224
|
-
...unsorted
|
|
225
|
-
]);
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Remove an edge from the graph.
|
|
231
|
-
*/
|
|
232
|
-
removeEdge({ source, target }) {
|
|
233
|
-
untracked(() => {
|
|
234
|
-
const outboundIndex = this._edges[this.getEdgeKey(source, "outbound")]?.findIndex((id) => id === target);
|
|
235
|
-
if (outboundIndex !== -1) {
|
|
236
|
-
this._edges[this.getEdgeKey(source, "outbound")].splice(outboundIndex, 1);
|
|
237
|
-
}
|
|
238
|
-
const inboundIndex = this._edges[this.getEdgeKey(target, "inbound")]?.findIndex((id) => id === source);
|
|
239
|
-
if (inboundIndex !== -1) {
|
|
240
|
-
this._edges[this.getEdgeKey(target, "inbound")].splice(inboundIndex, 1);
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Recursive depth-first traversal.
|
|
246
|
-
*
|
|
247
|
-
* @param options.node The node to start traversing from.
|
|
248
|
-
* @param options.direction The direction to traverse graph edges.
|
|
249
|
-
* @param options.filter A predicate to filter nodes which are passed to the `visitor` callback.
|
|
250
|
-
* @param options.visitor A callback which is called for each node visited during traversal.
|
|
251
|
-
*/
|
|
252
|
-
traverse({ node = this.root, direction = "outbound", filter, visitor }, path = []) {
|
|
253
|
-
if (path.includes(node.id)) {
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
66
|
+
traverse({ node = this._root, direction = "down", filter, visitor }, depth = 0) {
|
|
256
67
|
if (!filter || filter(node)) {
|
|
257
|
-
visitor?.(node,
|
|
258
|
-
...path,
|
|
259
|
-
node.id
|
|
260
|
-
]);
|
|
68
|
+
visitor?.(node, this.getPath(node.id));
|
|
261
69
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Get the path between two nodes in the graph.
|
|
277
|
-
*/
|
|
278
|
-
getPath({ source = "root", target }) {
|
|
279
|
-
const start = this.findNode(source);
|
|
280
|
-
if (!start) {
|
|
281
|
-
return void 0;
|
|
70
|
+
if (direction === "down") {
|
|
71
|
+
Object.values(node.children).forEach((child) => this.traverse({
|
|
72
|
+
node: child,
|
|
73
|
+
filter,
|
|
74
|
+
visitor
|
|
75
|
+
}));
|
|
76
|
+
} else if (direction === "up" && node.parent) {
|
|
77
|
+
this.traverse({
|
|
78
|
+
node: node.parent,
|
|
79
|
+
direction,
|
|
80
|
+
filter,
|
|
81
|
+
visitor
|
|
82
|
+
}, depth + 1);
|
|
282
83
|
}
|
|
283
|
-
let found;
|
|
284
|
-
this.traverse({
|
|
285
|
-
node: start,
|
|
286
|
-
filter: () => !found,
|
|
287
|
-
visitor: (node, path) => {
|
|
288
|
-
if (node.id === target) {
|
|
289
|
-
found = path;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
return found;
|
|
294
84
|
}
|
|
295
85
|
};
|
|
296
86
|
|
|
297
87
|
// packages/sdk/app-graph/src/graph-builder.ts
|
|
88
|
+
import { untracked } from "@preact/signals-core";
|
|
89
|
+
import { deepSignal as deepSignal2 } from "deepsignal/react";
|
|
298
90
|
import { EventSubscriptions } from "@dxos/async";
|
|
91
|
+
import { Keyboard } from "@dxos/keyboard";
|
|
92
|
+
import { getHostPlatform } from "@dxos/util";
|
|
93
|
+
var KEY_BINDING = "KeyBinding";
|
|
299
94
|
var GraphBuilder = class {
|
|
300
95
|
constructor() {
|
|
301
|
-
this.
|
|
302
|
-
this._unsubscribe = new
|
|
96
|
+
this._nodeBuilders = /* @__PURE__ */ new Map();
|
|
97
|
+
this._unsubscribe = /* @__PURE__ */ new Map();
|
|
303
98
|
}
|
|
304
99
|
/**
|
|
305
100
|
* Register a node builder which will be called in order to construct the graph.
|
|
306
101
|
*/
|
|
307
|
-
|
|
308
|
-
this.
|
|
102
|
+
addNodeBuilder(id, builder) {
|
|
103
|
+
this._nodeBuilders.set(id, builder);
|
|
309
104
|
return this;
|
|
310
105
|
}
|
|
311
106
|
/**
|
|
312
107
|
* Remove a node builder from the graph builder.
|
|
313
108
|
*/
|
|
314
|
-
|
|
315
|
-
this.
|
|
109
|
+
removeNodeBuilder(id) {
|
|
110
|
+
this._nodeBuilders.delete(id);
|
|
316
111
|
return this;
|
|
317
112
|
}
|
|
318
113
|
/**
|
|
319
|
-
* Construct the graph, starting by calling all registered
|
|
114
|
+
* Construct the graph, starting by calling all registered node builders on the root node.
|
|
115
|
+
* Node builders will be filtered out as they are used such that they are only used once on any given path.
|
|
320
116
|
* @param previousGraph If provided, the graph will be updated in place.
|
|
117
|
+
* @param startingPath If provided, the graph will be updated starting at the given path.
|
|
118
|
+
*/
|
|
119
|
+
build(previousGraph, startingPath = []) {
|
|
120
|
+
const graph = previousGraph ?? new Graph(this._createNode(() => graph, {
|
|
121
|
+
id: "root",
|
|
122
|
+
label: "Root"
|
|
123
|
+
}));
|
|
124
|
+
return this._build(graph, graph.root, startingPath);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Called recursively.
|
|
321
128
|
*/
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
unsubscribe
|
|
129
|
+
_build(graph, node, path = [], ignoreBuilders = []) {
|
|
130
|
+
graph._setPath(node.id, path);
|
|
131
|
+
const subscriptions = this._unsubscribe.get(node.id) ?? new EventSubscriptions();
|
|
132
|
+
subscriptions.clear();
|
|
133
|
+
Array.from(this._nodeBuilders.entries()).filter(([id]) => ignoreBuilders.findIndex((ignore) => ignore === id) === -1).forEach(([_, builder]) => {
|
|
134
|
+
const unsubscribe = builder(node);
|
|
135
|
+
unsubscribe && subscriptions.add(unsubscribe);
|
|
328
136
|
});
|
|
137
|
+
this._unsubscribe.set(node.id, subscriptions);
|
|
329
138
|
return graph;
|
|
330
139
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
140
|
+
_createNode(getGraph, partial, path = [], ignoreBuilders = []) {
|
|
141
|
+
const node = deepSignal2({
|
|
142
|
+
parent: null,
|
|
143
|
+
data: null,
|
|
144
|
+
properties: {},
|
|
145
|
+
childrenMap: {},
|
|
146
|
+
actionsMap: {},
|
|
147
|
+
// TODO(burdon): Document.
|
|
148
|
+
...partial,
|
|
149
|
+
get children() {
|
|
150
|
+
return Object.values(node.childrenMap);
|
|
151
|
+
},
|
|
152
|
+
get actions() {
|
|
153
|
+
return Object.values(node.actionsMap);
|
|
154
|
+
},
|
|
155
|
+
//
|
|
156
|
+
// Properties
|
|
157
|
+
//
|
|
158
|
+
addProperty: (key, value) => {
|
|
159
|
+
untracked(() => {
|
|
160
|
+
node.properties[key] = value;
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
removeProperty: (key) => {
|
|
164
|
+
untracked(() => {
|
|
165
|
+
delete node.properties[key];
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
//
|
|
169
|
+
// Nodes
|
|
170
|
+
//
|
|
171
|
+
addNode: (builder, ...partials) => {
|
|
172
|
+
return untracked(() => {
|
|
173
|
+
return partials.map((partial2) => {
|
|
174
|
+
const builders = [
|
|
175
|
+
...ignoreBuilders,
|
|
176
|
+
builder
|
|
177
|
+
];
|
|
178
|
+
const childPath = [
|
|
179
|
+
...path,
|
|
180
|
+
"childrenMap",
|
|
181
|
+
partial2.id
|
|
182
|
+
];
|
|
183
|
+
const child = this._createNode(getGraph, {
|
|
184
|
+
...partial2,
|
|
185
|
+
parent: node
|
|
186
|
+
}, childPath, builders);
|
|
187
|
+
node.childrenMap[child.id] = child;
|
|
188
|
+
this._build(getGraph(), child, childPath, builders);
|
|
189
|
+
return child;
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
removeNode: (id) => {
|
|
194
|
+
return untracked(() => {
|
|
195
|
+
const child = node.childrenMap[id];
|
|
196
|
+
delete node.childrenMap[id];
|
|
197
|
+
return child;
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
//
|
|
201
|
+
// Actions
|
|
202
|
+
//
|
|
203
|
+
addAction: (...partials) => {
|
|
204
|
+
return untracked(() => {
|
|
205
|
+
return partials.map((partial2) => {
|
|
206
|
+
const action = this._createAction(partial2);
|
|
207
|
+
let shortcut;
|
|
208
|
+
if (typeof action.keyBinding === "object") {
|
|
209
|
+
const availablePlatforms = Object.keys(action.keyBinding);
|
|
210
|
+
const platform = getHostPlatform();
|
|
211
|
+
shortcut = availablePlatforms.includes(platform) ? action.keyBinding[platform] : platform === "ios" ? action.keyBinding.macos : platform === "linux" || platform === "unknown" ? action.keyBinding.windows : void 0;
|
|
212
|
+
} else {
|
|
213
|
+
shortcut = action.keyBinding;
|
|
214
|
+
}
|
|
215
|
+
if (shortcut) {
|
|
216
|
+
Keyboard.singleton.getContext(path.join("/")).bind({
|
|
217
|
+
shortcut,
|
|
218
|
+
handler: () => {
|
|
219
|
+
action.invoke({
|
|
220
|
+
caller: KEY_BINDING
|
|
221
|
+
});
|
|
222
|
+
},
|
|
223
|
+
data: action.label
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
node.actionsMap[action.id] = action;
|
|
227
|
+
return action;
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
removeAction: (id) => {
|
|
232
|
+
return untracked(() => {
|
|
233
|
+
const action = node.actionsMap[id];
|
|
234
|
+
if (action.keyBinding) {
|
|
235
|
+
}
|
|
236
|
+
delete node.actionsMap[id];
|
|
237
|
+
return action;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
partial.actions && partial.actions.forEach((action) => node.addAction(action));
|
|
242
|
+
return node;
|
|
243
|
+
}
|
|
244
|
+
_createAction(partial) {
|
|
245
|
+
const action = deepSignal2({
|
|
246
|
+
properties: {},
|
|
247
|
+
...partial,
|
|
248
|
+
actionsMap: {},
|
|
249
|
+
get actions() {
|
|
250
|
+
return Object.values(action.actionsMap);
|
|
251
|
+
},
|
|
252
|
+
addAction: (...partials) => {
|
|
253
|
+
return untracked(() => {
|
|
254
|
+
return partials.map((partial2) => {
|
|
255
|
+
const subAction = this._createAction(partial2);
|
|
256
|
+
action.actionsMap[subAction.id] = subAction;
|
|
257
|
+
return subAction;
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
},
|
|
261
|
+
removeAction: (id) => {
|
|
262
|
+
return untracked(() => {
|
|
263
|
+
const subAction = action.actionsMap[id];
|
|
264
|
+
delete action.actionsMap[id];
|
|
265
|
+
return subAction;
|
|
266
|
+
});
|
|
267
|
+
},
|
|
268
|
+
addProperty: (key, value) => {
|
|
269
|
+
return untracked(() => {
|
|
270
|
+
action.properties[key] = value;
|
|
271
|
+
});
|
|
272
|
+
},
|
|
273
|
+
removeProperty: (key) => {
|
|
274
|
+
return untracked(() => {
|
|
275
|
+
delete action.properties[key];
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
partial.actions && partial.actions.forEach((subAction) => action.addAction(subAction));
|
|
280
|
+
return action;
|
|
339
281
|
}
|
|
340
282
|
};
|
|
283
|
+
|
|
284
|
+
// packages/sdk/app-graph/src/node.ts
|
|
285
|
+
var isGraphNode = (data) => data && typeof data === "object" ? "id" in data && "label" in data : false;
|
|
341
286
|
export {
|
|
342
287
|
Graph,
|
|
343
288
|
GraphBuilder,
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
isAction,
|
|
347
|
-
isActionGroup,
|
|
348
|
-
isActionLike,
|
|
349
|
-
isGraphNode,
|
|
350
|
-
manageNodes
|
|
289
|
+
KEY_BINDING,
|
|
290
|
+
isGraphNode
|
|
351
291
|
};
|
|
352
292
|
//# sourceMappingURL=index.mjs.map
|