@dxos/plugin-explorer 0.8.1 → 0.8.2-main.10c050d

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.
Files changed (170) hide show
  1. package/dist/lib/browser/ExplorerContainer-BBZ54DJS.mjs +37 -0
  2. package/dist/lib/browser/ExplorerContainer-BBZ54DJS.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-B2DMPSP5.mjs → chunk-73GQ46YO.mjs} +430 -170
  4. package/dist/lib/{node-esm/chunk-PZOORWFE.mjs.map → browser/chunk-73GQ46YO.mjs.map} +4 -4
  5. package/dist/lib/browser/{chunk-QLQLPZNI.mjs → chunk-73YTQHOT.mjs} +12 -11
  6. package/dist/lib/browser/chunk-73YTQHOT.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-M2BGAY6H.mjs +177 -0
  8. package/dist/lib/browser/chunk-M2BGAY6H.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-Z2SDLMQM.mjs → chunk-OBAFAA5V.mjs} +3 -3
  10. package/dist/lib/browser/{chunk-Z2SDLMQM.mjs.map → chunk-OBAFAA5V.mjs.map} +1 -1
  11. package/dist/lib/browser/chunk-SLB2F5AO.mjs +30 -0
  12. package/dist/lib/browser/chunk-SLB2F5AO.mjs.map +7 -0
  13. package/dist/lib/browser/index.mjs +15 -11
  14. package/dist/lib/browser/index.mjs.map +1 -1
  15. package/dist/lib/browser/{intent-resolver-NHHRWTOP.mjs → intent-resolver-FJDVBDE3.mjs} +5 -5
  16. package/dist/lib/browser/intent-resolver-FJDVBDE3.mjs.map +7 -0
  17. package/dist/lib/browser/meta.json +1 -1
  18. package/dist/lib/browser/meta.mjs +1 -1
  19. package/dist/lib/browser/{react-surface-N7TC6BMF.mjs → react-surface-H3YDMXAQ.mjs} +5 -5
  20. package/dist/lib/browser/types/index.mjs +2 -2
  21. package/dist/lib/node/{ExplorerContainer-73AHSBAG.cjs → ExplorerContainer-MVP2AM7R.cjs} +24 -16
  22. package/dist/lib/node/ExplorerContainer-MVP2AM7R.cjs.map +7 -0
  23. package/dist/lib/node/chunk-4T4LCT5R.cjs +52 -0
  24. package/dist/lib/node/chunk-4T4LCT5R.cjs.map +7 -0
  25. package/dist/lib/node/{chunk-HCDBN6NN.cjs → chunk-72H5HBTK.cjs} +429 -168
  26. package/dist/lib/node/chunk-72H5HBTK.cjs.map +7 -0
  27. package/dist/lib/node/{chunk-VB3QE6XY.cjs → chunk-BCDVG2CH.cjs} +6 -6
  28. package/dist/lib/node/{chunk-VB3QE6XY.cjs.map → chunk-BCDVG2CH.cjs.map} +1 -1
  29. package/dist/lib/node/{chunk-YLL7H7CZ.cjs → chunk-MLRYW4WQ.cjs} +15 -14
  30. package/dist/lib/node/chunk-MLRYW4WQ.cjs.map +7 -0
  31. package/dist/lib/node/chunk-NELWWGBU.cjs +204 -0
  32. package/dist/lib/node/chunk-NELWWGBU.cjs.map +7 -0
  33. package/dist/lib/node/index.cjs +34 -31
  34. package/dist/lib/node/index.cjs.map +1 -1
  35. package/dist/lib/node/{intent-resolver-EEOTX3OZ.cjs → intent-resolver-DRT67ZU4.cjs} +8 -8
  36. package/dist/lib/node/intent-resolver-DRT67ZU4.cjs.map +7 -0
  37. package/dist/lib/node/meta.cjs +3 -3
  38. package/dist/lib/node/meta.cjs.map +1 -1
  39. package/dist/lib/node/meta.json +1 -1
  40. package/dist/lib/node/{react-surface-WD4G2NRS.cjs → react-surface-6ESLSM33.cjs} +11 -11
  41. package/dist/lib/node/types/index.cjs +4 -4
  42. package/dist/lib/node/types/index.cjs.map +1 -1
  43. package/dist/lib/node-esm/ExplorerContainer-APGUQI4M.mjs +38 -0
  44. package/dist/lib/node-esm/ExplorerContainer-APGUQI4M.mjs.map +7 -0
  45. package/dist/lib/node-esm/{chunk-PZOORWFE.mjs → chunk-34X2VFQN.mjs} +430 -169
  46. package/dist/lib/{browser/chunk-B2DMPSP5.mjs.map → node-esm/chunk-34X2VFQN.mjs.map} +4 -4
  47. package/dist/lib/node-esm/{chunk-PUFSCMN4.mjs → chunk-3CMBLK6W.mjs} +3 -3
  48. package/dist/lib/node-esm/{chunk-PUFSCMN4.mjs.map → chunk-3CMBLK6W.mjs.map} +1 -1
  49. package/dist/lib/node-esm/{chunk-QZH2GDN5.mjs → chunk-N6VEANUZ.mjs} +12 -11
  50. package/dist/lib/node-esm/chunk-N6VEANUZ.mjs.map +7 -0
  51. package/dist/lib/node-esm/chunk-PVII2K2B.mjs +179 -0
  52. package/dist/lib/node-esm/chunk-PVII2K2B.mjs.map +7 -0
  53. package/dist/lib/node-esm/chunk-VSORIAHH.mjs +32 -0
  54. package/dist/lib/node-esm/chunk-VSORIAHH.mjs.map +7 -0
  55. package/dist/lib/node-esm/index.mjs +15 -11
  56. package/dist/lib/node-esm/index.mjs.map +1 -1
  57. package/dist/lib/node-esm/{intent-resolver-PTFKXAT4.mjs → intent-resolver-4RBV644N.mjs} +5 -5
  58. package/dist/lib/node-esm/intent-resolver-4RBV644N.mjs.map +7 -0
  59. package/dist/lib/node-esm/meta.json +1 -1
  60. package/dist/lib/node-esm/meta.mjs +1 -1
  61. package/dist/lib/node-esm/{react-surface-J5SW7VF2.mjs → react-surface-ZEVL3FXG.mjs} +5 -5
  62. package/dist/lib/node-esm/types/index.mjs +2 -2
  63. package/dist/types/src/components/Chart/Chart.d.ts.map +1 -1
  64. package/dist/types/src/components/ExplorerContainer.d.ts +4 -3
  65. package/dist/types/src/components/ExplorerContainer.d.ts.map +1 -1
  66. package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
  67. package/dist/types/src/components/Graph/D3ForceGraph.d.ts +14 -0
  68. package/dist/types/src/components/Graph/D3ForceGraph.d.ts.map +1 -0
  69. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts +6 -0
  70. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts.map +1 -0
  71. package/dist/types/src/components/Graph/ForceGraph.d.ts +8 -0
  72. package/dist/types/src/components/Graph/ForceGraph.d.ts.map +1 -0
  73. package/dist/types/src/components/Graph/{Graph.stories.d.ts → ForceGraph.stories.d.ts} +1 -1
  74. package/dist/types/src/components/Graph/ForceGraph.stories.d.ts.map +1 -0
  75. package/dist/types/src/components/Graph/adapter.d.ts +21 -0
  76. package/dist/types/src/components/Graph/adapter.d.ts.map +1 -0
  77. package/dist/types/src/components/Graph/index.d.ts +2 -2
  78. package/dist/types/src/components/Graph/index.d.ts.map +1 -1
  79. package/dist/types/src/components/Graph/testing.d.ts +14 -0
  80. package/dist/types/src/components/Graph/testing.d.ts.map +1 -0
  81. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  82. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +1 -1
  83. package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +1 -1
  84. package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +1 -1
  85. package/dist/types/src/components/Tree/testing/generator.d.ts +8 -0
  86. package/dist/types/src/components/Tree/testing/generator.d.ts.map +1 -0
  87. package/dist/types/src/components/Tree/testing/index.d.ts +2 -0
  88. package/dist/types/src/components/Tree/testing/index.d.ts.map +1 -0
  89. package/dist/types/src/components/Tree/types/index.d.ts +3 -0
  90. package/dist/types/src/components/Tree/types/index.d.ts.map +1 -0
  91. package/dist/types/src/components/Tree/types/tree.d.ts +83 -0
  92. package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -0
  93. package/dist/types/src/components/Tree/types/tree.test.d.ts +2 -0
  94. package/dist/types/src/components/Tree/types/tree.test.d.ts.map +1 -0
  95. package/dist/types/src/components/Tree/types/types.d.ts +8 -0
  96. package/dist/types/src/components/Tree/types/types.d.ts.map +1 -0
  97. package/dist/types/src/components/index.d.ts +2 -2
  98. package/dist/types/src/components/plot.d.ts.map +1 -1
  99. package/dist/types/src/hooks/index.d.ts +2 -0
  100. package/dist/types/src/hooks/index.d.ts.map +1 -0
  101. package/dist/types/src/hooks/useGraphModel.d.ts +4 -0
  102. package/dist/types/src/hooks/useGraphModel.d.ts.map +1 -0
  103. package/dist/types/src/index.d.ts +2 -1
  104. package/dist/types/src/index.d.ts.map +1 -1
  105. package/dist/types/src/translations.d.ts +2 -8
  106. package/dist/types/src/translations.d.ts.map +1 -1
  107. package/dist/types/src/types/schema.d.ts +6 -6
  108. package/dist/types/src/types/schema.d.ts.map +1 -1
  109. package/dist/types/src/types/types.d.ts +6 -6
  110. package/dist/types/src/types/types.d.ts.map +1 -1
  111. package/dist/types/tsconfig.tsbuildinfo +1 -1
  112. package/package.json +30 -27
  113. package/src/capabilities/intent-resolver.ts +2 -2
  114. package/src/components/ExplorerContainer.tsx +11 -4
  115. package/src/components/Globe/Globe.stories.tsx +13 -13
  116. package/src/components/Graph/D3ForceGraph.stories.tsx +64 -0
  117. package/src/components/Graph/D3ForceGraph.tsx +101 -0
  118. package/src/components/Graph/ForceGraph.stories.tsx +64 -0
  119. package/src/components/Graph/{Graph.tsx → ForceGraph.tsx} +19 -26
  120. package/src/components/Graph/adapter.ts +47 -0
  121. package/src/components/Graph/index.ts +2 -3
  122. package/src/components/Graph/testing.ts +57 -0
  123. package/src/components/Tree/Tree.stories.tsx +1 -1
  124. package/src/components/Tree/Tree.tsx +11 -18
  125. package/src/components/Tree/layout/HierarchicalEdgeBundling.ts +17 -19
  126. package/src/components/Tree/layout/RadialTree.ts +5 -7
  127. package/src/components/Tree/layout/TidyTree.ts +5 -6
  128. package/src/components/Tree/testing/generator.ts +46 -0
  129. package/src/components/Tree/testing/index.ts +5 -0
  130. package/src/components/Tree/types/index.ts +6 -0
  131. package/src/components/Tree/types/tree.test.ts +133 -0
  132. package/src/components/Tree/types/tree.ts +287 -0
  133. package/src/components/Tree/types/types.ts +41 -0
  134. package/src/hooks/index.ts +5 -0
  135. package/src/hooks/useGraphModel.ts +35 -0
  136. package/src/index.ts +2 -2
  137. package/src/meta.ts +2 -2
  138. package/src/types/schema.ts +5 -3
  139. package/src/types/types.ts +5 -5
  140. package/dist/lib/browser/ExplorerContainer-HL532ODG.mjs +0 -27
  141. package/dist/lib/browser/ExplorerContainer-HL532ODG.mjs.map +0 -7
  142. package/dist/lib/browser/chunk-QLQLPZNI.mjs.map +0 -7
  143. package/dist/lib/browser/chunk-SBLNE7FL.mjs +0 -205
  144. package/dist/lib/browser/chunk-SBLNE7FL.mjs.map +0 -7
  145. package/dist/lib/browser/intent-resolver-NHHRWTOP.mjs.map +0 -7
  146. package/dist/lib/node/ExplorerContainer-73AHSBAG.cjs.map +0 -7
  147. package/dist/lib/node/chunk-HCDBN6NN.cjs.map +0 -7
  148. package/dist/lib/node/chunk-OIHH6TVE.cjs +0 -236
  149. package/dist/lib/node/chunk-OIHH6TVE.cjs.map +0 -7
  150. package/dist/lib/node/chunk-YLL7H7CZ.cjs.map +0 -7
  151. package/dist/lib/node/intent-resolver-EEOTX3OZ.cjs.map +0 -7
  152. package/dist/lib/node-esm/ExplorerContainer-NMI55PYM.mjs +0 -28
  153. package/dist/lib/node-esm/ExplorerContainer-NMI55PYM.mjs.map +0 -7
  154. package/dist/lib/node-esm/chunk-QZH2GDN5.mjs.map +0 -7
  155. package/dist/lib/node-esm/chunk-SZRRNWYT.mjs +0 -207
  156. package/dist/lib/node-esm/chunk-SZRRNWYT.mjs.map +0 -7
  157. package/dist/lib/node-esm/intent-resolver-PTFKXAT4.mjs.map +0 -7
  158. package/dist/types/src/components/Graph/Graph.d.ts +0 -8
  159. package/dist/types/src/components/Graph/Graph.d.ts.map +0 -1
  160. package/dist/types/src/components/Graph/Graph.stories.d.ts.map +0 -1
  161. package/dist/types/src/components/Graph/graph-model.d.ts +0 -39
  162. package/dist/types/src/components/Graph/graph-model.d.ts.map +0 -1
  163. package/dist/types/src/components/Tree/types.d.ts +0 -8
  164. package/dist/types/src/components/Tree/types.d.ts.map +0 -1
  165. package/src/components/Graph/Graph.stories.tsx +0 -62
  166. package/src/components/Graph/graph-model.ts +0 -193
  167. package/src/components/Tree/types.ts +0 -40
  168. /package/dist/lib/browser/{react-surface-N7TC6BMF.mjs.map → react-surface-H3YDMXAQ.mjs.map} +0 -0
  169. /package/dist/lib/node/{react-surface-WD4G2NRS.cjs.map → react-surface-6ESLSM33.cjs.map} +0 -0
  170. /package/dist/lib/node-esm/{react-surface-J5SW7VF2.mjs.map → react-surface-ZEVL3FXG.mjs.map} +0 -0
@@ -0,0 +1,287 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Schema } from 'effect';
6
+
7
+ import { Type } from '@dxos/echo';
8
+ import { ObjectId, Ref, Expando } from '@dxos/echo-schema';
9
+ import { invariant } from '@dxos/invariant';
10
+ import { live } from '@dxos/live-object';
11
+
12
+ // TODO(burdon): Reconcile with @dxos/graph (i.e., common types).
13
+
14
+ export const TreeNodeType = Schema.Struct({
15
+ id: ObjectId,
16
+ children: Schema.mutable(Schema.Array(ObjectId)),
17
+ data: Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.Any })),
18
+ ref: Schema.optional(Ref(Expando)), // TODO(burdon): Generic type?
19
+ }).pipe(Schema.mutable);
20
+
21
+ export interface TreeNodeType extends Schema.Schema.Type<typeof TreeNodeType> {}
22
+
23
+ export const TreeType = Schema.Struct({
24
+ root: ObjectId,
25
+ nodes: Schema.mutable(Schema.Record({ key: ObjectId, value: TreeNodeType })),
26
+ }).pipe(
27
+ Type.Obj({
28
+ typename: 'dxos.org/type/Tree',
29
+ version: '0.1.0',
30
+ }),
31
+ );
32
+
33
+ export interface TreeType extends Schema.Schema.Type<typeof TreeType> {}
34
+
35
+ /**
36
+ * Wrapper object for tree.
37
+ */
38
+ export class Tree {
39
+ static create = (): TreeType => {
40
+ const id = ObjectId.random();
41
+ return live(TreeType, {
42
+ root: id,
43
+ nodes: {
44
+ [id]: {
45
+ id,
46
+ children: [],
47
+ data: { text: '' }, // TODO(burdon): Generic.
48
+ },
49
+ },
50
+ });
51
+ };
52
+
53
+ private _tree: TreeType;
54
+
55
+ constructor(tree?: TreeType) {
56
+ this._tree = tree ?? Tree.create();
57
+ }
58
+
59
+ get tree() {
60
+ return this._tree;
61
+ }
62
+
63
+ // TODO(burdon): Make reactive.
64
+ get size() {
65
+ return Object.keys(this._tree.nodes).length;
66
+ }
67
+
68
+ get root() {
69
+ return this.getNode(this._tree.root);
70
+ }
71
+
72
+ //
73
+ // Traversal
74
+ //
75
+
76
+ /**
77
+ * Recursively traverse the tree until the callback returns a value.
78
+ */
79
+ tranverse<T>(
80
+ callback: (node: TreeNodeType, depth: number) => T | void,
81
+ root: ObjectId = this._tree.root,
82
+ depth = 0,
83
+ ): T | void {
84
+ const node = this._tree.nodes[root];
85
+ const result = callback(node, depth);
86
+ if (result !== undefined) {
87
+ return result;
88
+ }
89
+
90
+ for (const childId of node.children) {
91
+ const result = this.tranverse(callback, childId, depth + 1);
92
+ if (result !== undefined) {
93
+ return result;
94
+ }
95
+ }
96
+ }
97
+
98
+ getNode(id: ObjectId): TreeNodeType {
99
+ const node = this._tree.nodes[id];
100
+ invariant(node);
101
+ return node;
102
+ }
103
+
104
+ /**
105
+ * Get the children of a node.
106
+ */
107
+ getChildNodes(node: TreeNodeType): Array<TreeNodeType> {
108
+ return node.children.map((id) => this.getNode(id));
109
+ }
110
+
111
+ /**
112
+ * Get the parent of a node.
113
+ */
114
+ getParent(node: TreeNodeType): TreeNodeType | null {
115
+ const parent = this.tranverse((n) => {
116
+ if (n.children.includes(node.id)) {
117
+ return n;
118
+ }
119
+ });
120
+
121
+ return parent ?? null;
122
+ }
123
+
124
+ /**
125
+ * Get the next node in the tree.
126
+ */
127
+ getNext(node: TreeNodeType, hierarchical = true): TreeNodeType | undefined {
128
+ if (hierarchical && node.children.length) {
129
+ // First child.
130
+ return this.getChildNodes(node)[0];
131
+ } else {
132
+ const parent = this.getParent(node);
133
+ if (parent) {
134
+ const idx = this.getChildNodes(parent).findIndex(({ id }) => id === node.id);
135
+ if (idx < parent.children.length - 1) {
136
+ // Next sibling.
137
+ return this.getNode(parent.children[idx + 1]);
138
+ } else {
139
+ // Get parent's next sibling.
140
+ return this.getNext(parent, false);
141
+ }
142
+ }
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Get the previous node in the tree.
148
+ */
149
+ getPrevious(node: TreeNodeType, hierarchical = true): TreeNodeType | undefined {
150
+ const parent = this.getParent(node)!;
151
+ const idx = this.getChildNodes(parent).findIndex(({ id }) => id === node.id);
152
+ if (idx === 0) {
153
+ if (hierarchical) {
154
+ return parent;
155
+ }
156
+ } else {
157
+ const previous = this.getNode(parent.children[idx - 1]);
158
+ if (hierarchical && previous.children.length) {
159
+ return this.getLastDescendent(previous);
160
+ }
161
+
162
+ return previous;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Get the last descendent of a node.
168
+ */
169
+ getLastDescendent(node: TreeNodeType): TreeNodeType | undefined {
170
+ const children = this.getChildNodes(node);
171
+ const last = children.length ? children[children.length - 1] : undefined;
172
+ if (last) {
173
+ return this.getLastDescendent(last);
174
+ }
175
+
176
+ return node;
177
+ }
178
+
179
+ //
180
+ // Mutations
181
+ //
182
+
183
+ /**
184
+ * Clear tree.
185
+ */
186
+ clear(): void {
187
+ const root = this._tree.nodes[this._tree.root];
188
+ root.children.length = 0;
189
+ this._tree.nodes = {
190
+ [root.id]: root,
191
+ };
192
+ }
193
+
194
+ /**
195
+ * Add node.
196
+ */
197
+ addNode(parent: TreeNodeType, node?: TreeNodeType, index?: number): TreeNodeType {
198
+ if (!node) {
199
+ const id = ObjectId.random();
200
+ node = { id, children: [], data: { text: '' } }; // TODO(burdon): Generic.
201
+ }
202
+
203
+ this._tree.nodes[node.id] = node;
204
+ parent.children.splice(index ?? parent.children.length, 0, node.id);
205
+ return node;
206
+ }
207
+
208
+ /**
209
+ * Delete node.
210
+ */
211
+ deleteNode(parent: TreeNodeType, id: ObjectId): TreeNodeType | undefined {
212
+ const node = this._tree.nodes[id];
213
+ if (!node) {
214
+ return undefined;
215
+ }
216
+
217
+ delete this._tree.nodes[node.id];
218
+ const idx = parent.children.findIndex((child) => child === id);
219
+ if (idx !== -1) {
220
+ parent.children.splice(idx, 1);
221
+ }
222
+
223
+ return node;
224
+ }
225
+
226
+ /**
227
+ * Move child node.
228
+ */
229
+ moveNode(node: TreeNodeType, from: number, to: number): TreeNodeType | null {
230
+ invariant(from >= 0 && from < node.children.length);
231
+ invariant(to >= 0 && to < node.children.length);
232
+ if (from === to) {
233
+ return null;
234
+ }
235
+
236
+ const child = node.children[from];
237
+ node.children.splice(from, 1);
238
+ node.children.splice(to, 0, child);
239
+ return this.getNode(child);
240
+ }
241
+
242
+ /**
243
+ * Indent node.
244
+ */
245
+ indentNode(node: TreeNodeType): void {
246
+ const parent = this.getParent(node);
247
+ if (!parent) {
248
+ return;
249
+ }
250
+
251
+ const idx = parent.children.findIndex((child) => child === node.id);
252
+ if (idx < 1 || idx >= parent.children.length) {
253
+ return;
254
+ }
255
+
256
+ const previous = this.getNode(parent.children[idx - 1]);
257
+ parent.children.splice(idx, 1);
258
+ previous.children.push(node.id);
259
+ }
260
+
261
+ /**
262
+ * Unindent node.
263
+ */
264
+ unindentNode(node: TreeNodeType): void {
265
+ const parent = this.getParent(node);
266
+ if (!parent) {
267
+ return;
268
+ }
269
+
270
+ const ancestor = this.getParent(parent);
271
+ if (!ancestor) {
272
+ return;
273
+ }
274
+
275
+ // Remove node from parent.
276
+ const nodeIdx = parent.children.findIndex((id) => id === node.id);
277
+ const [_, ...rest] = parent.children.splice(nodeIdx, parent.children.length - nodeIdx);
278
+ parent.children.splice(nodeIdx, parent.children.length - nodeIdx);
279
+
280
+ // Add to ancestor.
281
+ const parentIdx = this.getChildNodes(ancestor).findIndex((n) => n.id === parent.id);
282
+ ancestor.children.splice(parentIdx + 1, 0, node.id);
283
+
284
+ // Transplant following siblings to current node.
285
+ node.children.push(...rest);
286
+ }
287
+ }
@@ -0,0 +1,41 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type GraphModel } from '@dxos/graph';
6
+
7
+ export type TreeNode = {
8
+ id: string;
9
+ label?: string;
10
+ children?: TreeNode[];
11
+ };
12
+
13
+ export const mapGraphToTreeData = (model: GraphModel, maxDepth = 8): TreeNode | undefined => {
14
+ // TODO(burdon): Convert to common/graph.
15
+ // const mapNode = (node: N, depth = 0): TreeNode => {
16
+ // const treeNode: TreeNode = {
17
+ // id: model.idAccessor(node),
18
+ // label: model.idAccessor(node).slice(0, 8),
19
+ // };
20
+
21
+ // const links = model.graph.links.filter((link) => link.source === treeNode.id);
22
+ // if (depth < maxDepth) {
23
+ // treeNode.children = links.map((link) =>
24
+ // mapNode(model.graph.nodes.find((node) => model.idAccessor(node) === link.target)!, depth + 1),
25
+ // );
26
+ // }
27
+
28
+ // return treeNode;
29
+ // };
30
+
31
+ let data: TreeNode | undefined;
32
+ // TODO(burdon): Selection model.
33
+ // if (model.selected) {
34
+ // const node = model.graph.nodes.find((node) => model.idAccessor(node) === model.selected);
35
+ // if (node) {
36
+ // data = mapNode(node);
37
+ // }
38
+ // }
39
+
40
+ return data;
41
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './useGraphModel';
@@ -0,0 +1,35 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { useEffect, useState } from 'react';
6
+
7
+ import { type Filter, type Space } from '@dxos/client/echo';
8
+ import { SpaceGraphModel, type SpaceGraphModelOptions } from '@dxos/schema';
9
+
10
+ // TODO(burdon): Factor out.
11
+ export const useGraphModel = (
12
+ space: Space | undefined,
13
+ filter?: Filter.Any | undefined,
14
+ options?: SpaceGraphModelOptions,
15
+ ): SpaceGraphModel | undefined => {
16
+ const [model, setModel] = useState<SpaceGraphModel | undefined>(undefined);
17
+ useEffect(() => {
18
+ if (!space) {
19
+ void model?.close();
20
+ setModel(undefined);
21
+ return;
22
+ }
23
+
24
+ // TODO(burdon): Does this need to be a dependency?
25
+ if (!model) {
26
+ const model = new SpaceGraphModel().setFilter(filter).setOptions(options);
27
+ void model.open(space);
28
+ setModel(model);
29
+ } else {
30
+ model.setFilter(filter).setOptions(options);
31
+ }
32
+ }, [space, filter, options]);
33
+
34
+ return model;
35
+ };
package/src/index.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- // TODO(burdon): Factor out.
6
5
  export * from './components';
6
+ export * from './hooks';
7
+ export * from './meta';
7
8
 
8
9
  export * from './ExplorerPlugin';
9
- export * from './meta';
package/src/meta.ts CHANGED
@@ -11,7 +11,7 @@ export const meta: PluginMeta = {
11
11
  name: 'Explorer',
12
12
  description: 'Install this plugin to view a hypergraph of all objects inside of your Space.',
13
13
  icon: 'ph--graph--regular',
14
- source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/experimental/plugin-explorer',
15
- tags: ['experimental'],
14
+ source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-explorer',
15
+ tags: ['labs'],
16
16
  screenshots: ['https://dxos.network/plugin-details-explorer-dark.png'],
17
17
  };
@@ -2,13 +2,15 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { S, TypedObject } from '@dxos/echo-schema';
5
+ import { Schema } from 'effect';
6
+
7
+ import { TypedObject } from '@dxos/echo-schema';
6
8
 
7
9
  // TODO(burdon): Clashes with sdk/view.
8
10
  export class ViewType extends TypedObject({
9
11
  typename: 'dxos.org/type/ExplorerView',
10
12
  version: '0.1.0',
11
13
  })({
12
- name: S.optional(S.String),
13
- type: S.String,
14
+ name: Schema.optional(Schema.String),
15
+ type: Schema.String,
14
16
  }) {}
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { S } from '@dxos/echo-schema';
5
+ import { Schema } from 'effect';
6
6
 
7
7
  import { ViewType } from './schema';
8
8
  import { EXPLORER_PLUGIN } from '../meta';
@@ -10,11 +10,11 @@ import { EXPLORER_PLUGIN } from '../meta';
10
10
  export namespace ExplorerAction {
11
11
  const EXPLORER_ACTION = `${EXPLORER_PLUGIN}/action`;
12
12
 
13
- export class Create extends S.TaggedClass<Create>()(`${EXPLORER_ACTION}/create`, {
14
- input: S.Struct({
15
- name: S.optional(S.String),
13
+ export class Create extends Schema.TaggedClass<Create>()(`${EXPLORER_ACTION}/create`, {
14
+ input: Schema.Struct({
15
+ name: Schema.optional(Schema.String),
16
16
  }),
17
- output: S.Struct({
17
+ output: Schema.Struct({
18
18
  object: ViewType,
19
19
  }),
20
20
  }) {}
@@ -1,27 +0,0 @@
1
- import {
2
- Graph
3
- } from "./chunk-SBLNE7FL.mjs";
4
-
5
- // packages/plugins/plugin-explorer/src/components/ExplorerContainer.tsx
6
- import React from "react";
7
- import { useGlobalSearch } from "@dxos/plugin-search";
8
- import { getSpace } from "@dxos/react-client/echo";
9
- import { StackItem } from "@dxos/react-ui-stack";
10
- var ExplorerContainer = ({ view, role }) => {
11
- const space = getSpace(view);
12
- const { match } = useGlobalSearch();
13
- if (!space) {
14
- return null;
15
- }
16
- return /* @__PURE__ */ React.createElement(StackItem.Content, {
17
- size: role === "section" ? "square" : "intrinsic"
18
- }, /* @__PURE__ */ React.createElement(Graph, {
19
- space,
20
- match
21
- }));
22
- };
23
- var ExplorerContainer_default = ExplorerContainer;
24
- export {
25
- ExplorerContainer_default as default
26
- };
27
- //# sourceMappingURL=ExplorerContainer-HL532ODG.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/components/ExplorerContainer.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useGlobalSearch } from '@dxos/plugin-search';\nimport { getSpace } from '@dxos/react-client/echo';\nimport { StackItem } from '@dxos/react-ui-stack';\n\nimport { Graph } from './Graph';\nimport { type ViewType } from '../types';\n\nconst ExplorerContainer = ({ view, role }: { view: ViewType; role: string }) => {\n const space = getSpace(view);\n const { match } = useGlobalSearch();\n\n if (!space) {\n return null;\n }\n\n return (\n <StackItem.Content size={role === 'section' ? 'square' : 'intrinsic'}>\n <Graph space={space} match={match} />\n </StackItem.Content>\n );\n};\n\nexport default ExplorerContainer;\n"],
5
- "mappings": ";;;;;AAIA,OAAOA,WAAW;AAElB,SAASC,uBAAuB;AAChC,SAASC,gBAAgB;AACzB,SAASC,iBAAiB;AAK1B,IAAMC,oBAAoB,CAAC,EAAEC,MAAMC,KAAI,MAAoC;AACzE,QAAMC,QAAQC,SAASH,IAAAA;AACvB,QAAM,EAAEI,MAAK,IAAKC,gBAAAA;AAElB,MAAI,CAACH,OAAO;AACV,WAAO;EACT;AAEA,SACE,sBAAA,cAACI,UAAUC,SAAO;IAACC,MAAMP,SAAS,YAAY,WAAW;KACvD,sBAAA,cAACQ,OAAAA;IAAMP;IAAcE;;AAG3B;AAEA,IAAA,4BAAeL;",
6
- "names": ["React", "useGlobalSearch", "getSpace", "StackItem", "ExplorerContainer", "view", "role", "space", "getSpace", "match", "useGlobalSearch", "StackItem", "Content", "size", "Graph"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/schema.ts", "../../../src/types/types.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { S, TypedObject } from '@dxos/echo-schema';\n\n// TODO(burdon): Clashes with sdk/view.\nexport class ViewType extends TypedObject({\n typename: 'dxos.org/type/ExplorerView',\n version: '0.1.0',\n})({\n name: S.optional(S.String),\n type: S.String,\n}) {}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { S } from '@dxos/echo-schema';\n\nimport { ViewType } from './schema';\nimport { EXPLORER_PLUGIN } from '../meta';\n\nexport namespace ExplorerAction {\n const EXPLORER_ACTION = `${EXPLORER_PLUGIN}/action`;\n\n export class Create extends S.TaggedClass<Create>()(`${EXPLORER_ACTION}/create`, {\n input: S.Struct({\n name: S.optional(S.String),\n }),\n output: S.Struct({\n object: ViewType,\n }),\n }) {}\n}\n"],
5
- "mappings": ";;;;;AAIA,SAASA,GAAGC,mBAAmB;AAGxB,IAAMC,WAAN,cAAuBC,YAAY;EACxCC,UAAU;EACVC,SAAS;AACX,CAAA,EAAG;EACDC,MAAMC,EAAEC,SAASD,EAAEE,MAAM;EACzBC,MAAMH,EAAEE;AACV,CAAA,EAAA;AAAI;;;ACTJ,SAASE,KAAAA,UAAS;;UAKDC,iBAAAA;AACf,QAAMC,kBAAkB,GAAGC,eAAAA;EAEpB,MAAMC,eAAeC,GAAEC,YAAW,EAAW,GAAGJ,eAAAA,WAA0B;IAC/EK,OAAOF,GAAEG,OAAO;MACdC,MAAMJ,GAAEK,SAASL,GAAEM,MAAM;IAC3B,CAAA;IACAC,QAAQP,GAAEG,OAAO;MACfK,QAAQC;IACV,CAAA;EACF,CAAA,EAAA;EAAI;kBAPSV,SAAAA;AAQf,GAXiBH,mBAAAA,iBAAAA,CAAAA,EAAAA;",
6
- "names": ["S", "TypedObject", "ViewType", "TypedObject", "typename", "version", "name", "S", "optional", "String", "type", "S", "ExplorerAction", "EXPLORER_ACTION", "EXPLORER_PLUGIN", "Create", "S", "TaggedClass", "input", "Struct", "name", "optional", "String", "output", "object", "ViewType"]
7
- }
@@ -1,205 +0,0 @@
1
- // packages/plugins/plugin-explorer/src/components/Graph/graph-model.ts
2
- import { getSchema, getSchemaDXN, AST, ReferenceAnnotationId, SchemaValidator, StoredSchema } from "@dxos/echo-schema";
3
- import { GraphModel } from "@dxos/gem-spore";
4
- import { log } from "@dxos/log";
5
- import { CollectionType } from "@dxos/plugin-space/types";
6
- import { Filter } from "@dxos/react-client/echo";
7
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-explorer/src/components/Graph/graph-model.ts";
8
- var SpaceGraphModel = class extends GraphModel {
9
- constructor(_options = {}) {
10
- super();
11
- this._options = _options;
12
- this._graph = {
13
- nodes: [],
14
- links: []
15
- };
16
- }
17
- get graph() {
18
- return this._graph;
19
- }
20
- get objects() {
21
- return this._objects ?? [];
22
- }
23
- // TODO(burdon): Alternative diagram types:
24
- // - https://observablehq.com/@d3/radial-tree/2
25
- // - https://observablehq.com/@d3/disjoint-force-directed-graph/2
26
- // - https://observablehq.com/@mbostock/tadpoles
27
- // - https://observablehq.com/@d3/psr-b1919-21
28
- // - https://vasturiano.github.io/react-force-graph/example/basic (3D)
29
- async open(space, objectId) {
30
- if (!this._schemaSubscription) {
31
- const schemaaQuery = space.db.schemaRegistry.query({});
32
- const schemas = await schemaaQuery.run();
33
- const onSchemaUpdate = ({ results }) => this._schema = results;
34
- this._schemaSubscription = schemaaQuery.subscribe(onSchemaUpdate);
35
- onSchemaUpdate({
36
- results: schemas
37
- });
38
- this._objectsSubscription = space.db.query(Filter.not(Filter.or(Filter.schema(StoredSchema), Filter.schema(CollectionType)))).subscribe(({ objects }) => {
39
- this._objects = objects;
40
- const currentNodes = this._graph.nodes;
41
- this._graph.nodes = [];
42
- this._graph.links = [];
43
- const addSchema = (typename) => {
44
- const current = currentNodes.find((node) => node.id === typename);
45
- if (typename) {
46
- this._graph.nodes.push({
47
- ...current,
48
- id: typename,
49
- type: "schema",
50
- data: {
51
- typename
52
- }
53
- });
54
- }
55
- };
56
- space.db.graph.schemaRegistry.schemas.forEach((schema) => {
57
- const typename = getSchemaDXN(schema)?.typename;
58
- if (typename) {
59
- addSchema(typename);
60
- }
61
- });
62
- this._schema?.forEach((schema) => {
63
- const typename = getSchemaDXN(schema)?.typename;
64
- if (typename) {
65
- addSchema(typename);
66
- }
67
- });
68
- this._objects.forEach((object) => {
69
- const schema = getSchema(object);
70
- if (schema) {
71
- const typename = getSchemaDXN(schema)?.typename;
72
- if (typename) {
73
- const current = currentNodes.find((node) => node.id === object.id);
74
- this._graph.nodes.push({
75
- ...current,
76
- id: object.id,
77
- type: "object",
78
- data: {
79
- typename,
80
- object
81
- }
82
- });
83
- const schemaNode = this._graph.nodes.find((node) => node.type === "schema" && node.data.typename === typename);
84
- if (schemaNode) {
85
- this._graph.links.push({
86
- id: `${object.id}-${schemaNode.id}`,
87
- source: object.id,
88
- target: schemaNode.id
89
- });
90
- } else {
91
- log.info("schema node not found", {
92
- typename
93
- }, {
94
- F: __dxlog_file,
95
- L: 147,
96
- S: this,
97
- C: (f, a) => f(...a)
98
- });
99
- }
100
- AST.getPropertySignatures(schema.ast).forEach((prop) => {
101
- if (!SchemaValidator.hasTypeAnnotation(schema, prop.name.toString(), ReferenceAnnotationId)) {
102
- return;
103
- }
104
- const value = object[String(prop.name)];
105
- if (value) {
106
- const refs = Array.isArray(value) ? value : [
107
- value
108
- ];
109
- for (const ref of refs) {
110
- if (objects.findIndex((obj) => obj.id === ref.id) !== -1) {
111
- this._graph.links.push({
112
- id: `${object.id}-${String(prop.name)}-${ref.id}`,
113
- source: object.id,
114
- target: ref.id
115
- });
116
- }
117
- }
118
- }
119
- });
120
- }
121
- }
122
- });
123
- this.triggerUpdate();
124
- }, {
125
- fire: true
126
- });
127
- }
128
- this.setSelected(objectId);
129
- return this;
130
- }
131
- close() {
132
- this._schemaSubscription?.();
133
- this._schemaSubscription = void 0;
134
- this._objectsSubscription?.();
135
- this._objectsSubscription = void 0;
136
- return this;
137
- }
138
- };
139
-
140
- // packages/plugins/plugin-explorer/src/components/Graph/Graph.tsx
141
- import { forceLink, forceManyBody } from "d3";
142
- import ForceGraph from "force-graph";
143
- import React, { useEffect, useRef } from "react";
144
- import { useResizeDetector } from "react-resize-detector";
145
- import { filterObjectsSync } from "@dxos/plugin-search";
146
- import { useAsyncState } from "@dxos/react-ui";
147
- var Graph = ({ space, match }) => {
148
- const { ref, width, height } = useResizeDetector({
149
- refreshRate: 200
150
- });
151
- const rootRef = useRef(null);
152
- const forceGraph = useRef();
153
- const [model] = useAsyncState(async () => space ? new SpaceGraphModel({
154
- schema: true
155
- }).open(space) : void 0, [
156
- space
157
- ]);
158
- const filteredRef = useRef();
159
- filteredRef.current = filterObjectsSync(model?.objects ?? [], match);
160
- useEffect(() => {
161
- if (rootRef.current) {
162
- forceGraph.current = new ForceGraph(rootRef.current).nodeRelSize(6).nodeLabel((node) => {
163
- if (node.type === "schema") {
164
- return node.data.typename;
165
- }
166
- return node.id;
167
- }).nodeAutoColorBy((node) => node.type === "schema" ? "schema" : node.data.typename).linkColor(() => "rgba(255,255,255,0.25)");
168
- }
169
- return () => {
170
- forceGraph.current?.pauseAnimation().graphData({
171
- nodes: [],
172
- links: []
173
- });
174
- forceGraph.current = void 0;
175
- };
176
- }, []);
177
- useEffect(() => {
178
- if (forceGraph.current && width && height && model) {
179
- forceGraph.current.pauseAnimation().width(width).height(height).onEngineStop(() => {
180
- handleZoomToFit();
181
- }).d3Force("link", forceLink().distance(160).strength(0.5)).d3Force("charge", forceManyBody().strength(-30)).graphData(model.graph).warmupTicks(100).cooldownTime(1e3).resumeAnimation();
182
- }
183
- }, [
184
- model,
185
- width,
186
- height
187
- ]);
188
- const handleZoomToFit = () => {
189
- forceGraph.current?.zoomToFit(400, 40);
190
- };
191
- return /* @__PURE__ */ React.createElement("div", {
192
- ref,
193
- className: "relative grow",
194
- onClick: handleZoomToFit
195
- }, /* @__PURE__ */ React.createElement("div", {
196
- ref: rootRef,
197
- className: "absolute inset-0"
198
- }));
199
- };
200
-
201
- export {
202
- SpaceGraphModel,
203
- Graph
204
- };
205
- //# sourceMappingURL=chunk-SBLNE7FL.mjs.map