@reltio/graph 1.4.1585 → 1.4.1586-mui5

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 (164) hide show
  1. package/index.ts +1 -0
  2. package/package.json +26 -9
  3. package/public/bundle.js +205 -0
  4. package/public/bundle.js.LICENSE.txt +88 -0
  5. package/public/package.json +29 -0
  6. package/scripts/build/index.js +20 -0
  7. package/src/__tests__/GraphView.test.tsx +25 -0
  8. package/src/components/CircleLayout/CircleLayout.tsx +76 -0
  9. package/src/components/CircleLayout/__tests__/CircleLayout.test.tsx +194 -0
  10. package/src/components/GotoButton/GotoButton.tsx +23 -0
  11. package/src/components/GotoButton/__tests__/GotoButton.test.tsx +33 -0
  12. package/src/components/GotoButton/styles.ts +15 -0
  13. package/src/components/GraphArea/GraphArea.tsx +113 -0
  14. package/src/components/GraphArea/__tests__/GraphArea.test.tsx +202 -0
  15. package/src/components/GraphArea/styles.ts +30 -0
  16. package/src/components/GraphLayoutSelector/GraphLayoutSelector.tsx +43 -0
  17. package/src/components/GraphLayoutSelector/__tests__/GraphLayoutSelector.spec.tsx +44 -0
  18. package/src/components/GraphLayoutSelector/styles.ts +15 -0
  19. package/src/components/GraphPerspectiveView/GraphPerspectiveView.tsx +58 -0
  20. package/src/components/GraphPerspectiveView/__tests__/GraphPerspectiveView.test.tsx +115 -0
  21. package/src/components/GraphPerspectiveView/__tests__/useGraphLoader.test.tsx +1519 -0
  22. package/src/components/GraphPerspectiveView/__tests__/useRelationshipTable.test.tsx +1003 -0
  23. package/src/components/GraphPerspectiveView/__tests__/useSelectedEntity.test.tsx +373 -0
  24. package/src/components/GraphPerspectiveView/styles.ts +34 -0
  25. package/src/components/GraphRightSidePanel/GraphRightSidePanel.tsx +27 -0
  26. package/src/components/GraphRightSidePanel/__tests__/GraphRightSidePanel.test.tsx +18 -0
  27. package/src/components/GraphRightSidePanel/icons/relationship-icon.svg +3 -0
  28. package/src/components/GraphRightSidePanel/styles.ts +8 -0
  29. package/src/components/GraphTypeSelector/GraphTypeSelector.tsx +56 -0
  30. package/src/components/GraphTypeSelector/__tests__/GraphTypeSelector.test.tsx +109 -0
  31. package/src/components/GraphTypeSelector/styles.ts +17 -0
  32. package/src/components/HierarchyLayout/HierarchyLayout.ts +102 -0
  33. package/src/components/HierarchyLayout/__tests__/HierarchyLayout.spec.tsx +241 -0
  34. package/src/components/HierarchyLayout/__tests__/buildHierarchy.spec.ts +130 -0
  35. package/src/components/HierarchyLayout/__tests__/calculations.spec.ts +230 -0
  36. package/src/components/HierarchyLayout/buildHierarchy.ts +109 -0
  37. package/src/components/HierarchyLayout/calculations.ts +86 -0
  38. package/src/components/RightPanelEntityDetails/RightPanelEntityDetails.tsx +33 -0
  39. package/src/components/RightPanelEntityDetails/__tests__/RightPanelEntityDetails.test.tsx +39 -0
  40. package/src/components/RightPanelEntityDetails/styles.ts +12 -0
  41. package/src/components/RightPanelProfileBand/RightPanelProfileBand.tsx +33 -0
  42. package/src/components/RightPanelProfileBand/__tests__/RightPanelProfileBand.test.tsx +67 -0
  43. package/src/components/RightPanelProfileBand/styles.ts +8 -0
  44. package/src/components/RightPanelRelationship/RightPanelRelationship.tsx +25 -0
  45. package/src/components/RightPanelRelationship/__tests__/RightPanelRelationship.test.tsx +18 -0
  46. package/src/components/RightPanelRelationship/components/CollapsibleTable/CollapsibleTable.tsx +100 -0
  47. package/src/components/RightPanelRelationship/components/CollapsibleTable/TableHead.tsx +38 -0
  48. package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/CollapsibleTable.test.tsx +169 -0
  49. package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/TableHead.test.tsx +107 -0
  50. package/src/components/RightPanelRelationship/components/CollapsibleTable/styles.ts +38 -0
  51. package/src/components/RightPanelRelationship/components/CollapsibleTable/types.ts +20 -0
  52. package/src/components/RightPanelRelationship/components/DeleteRelationDialog/DeleteRelationDialog.tsx +34 -0
  53. package/src/components/RightPanelRelationship/components/DeleteRelationDialog/__tests__/DeleteRelationDialog.test.tsx +46 -0
  54. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationButton.tsx +43 -0
  55. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationDialog.tsx +121 -0
  56. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationButton.test.tsx +80 -0
  57. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationDialog.test.tsx +262 -0
  58. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/mockdata.ts +75 -0
  59. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/styles.ts +25 -0
  60. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/useCreatableInOutRelationTypes.ts +13 -0
  61. package/src/components/RightPanelRelationship/components/RelationshipTable/RelationshipTable.tsx +126 -0
  62. package/src/components/RightPanelRelationship/components/RelationshipTable/__tests__/RelationshipTable.test.tsx +176 -0
  63. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ControlsCellRenderer.tsx +59 -0
  64. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/DefaultCellRenderer.tsx +29 -0
  65. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ExpandedRowRenderer.tsx +94 -0
  66. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/HeadCellRenderer.tsx +34 -0
  67. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ProfileCellRenderer.tsx +41 -0
  68. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ControlsCellRenderer.test.tsx +80 -0
  69. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/DefaultCellRenderer.test.tsx +47 -0
  70. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ExpandedRowRenderer.test.tsx +166 -0
  71. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/HeadCellRenderer.test.tsx +23 -0
  72. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ProfileCellRenderer.test.tsx +47 -0
  73. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/DeleteRelationButton.tsx +32 -0
  74. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/__tests__/DeleteRelationButton.test.tsx +28 -0
  75. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/styles.ts +113 -0
  76. package/src/components/RightPanelRelationship/components/RelationshipTable/styles.ts +36 -0
  77. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFilters.tsx +41 -0
  78. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/RelationshipsFiltersDialog.tsx +91 -0
  79. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/__tests__/RelationshipsFilterDialog.test.tsx +192 -0
  80. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/styles.ts +34 -0
  81. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/RelationshipsSearchTextField.tsx +31 -0
  82. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/__tests__/RelationshipsSearchTextField.test.tsx +43 -0
  83. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/styles.ts +17 -0
  84. package/src/components/RightPanelRelationship/components/RelationshipsFilters/__tests__/RelationshipsFilters.test.tsx +76 -0
  85. package/src/components/RightPanelRelationship/components/RelationshipsFilters/styles.ts +19 -0
  86. package/src/components/RightPanelRelationship/styles.ts +20 -0
  87. package/src/components/SigmaCustomRenderers/SigmaCustomRenderersContainer.tsx +16 -0
  88. package/src/components/SigmaGraphContainer/SigmaGraphContainer.tsx +55 -0
  89. package/src/components/SigmaGraphContainer/__tests__/SigmaGraphContainer.test.tsx +25 -0
  90. package/src/components/SigmaGraphResizer/SigmaGraphResizer.tsx +13 -0
  91. package/src/components/SigmaGraphResizer/__tests__/SigmaGraphResizer.test.tsx +28 -0
  92. package/src/components/TreeLayout/TreeLayout.tsx +33 -0
  93. package/src/components/TreeLayout/__tests__/TreeLayout.test.tsx +42 -0
  94. package/src/components/TreeLayout/styles.ts +10 -0
  95. package/src/components/ZoomSlider/ZoomSlider.tsx +90 -0
  96. package/src/components/ZoomSlider/__tests__/ZoomSlider.test.tsx +84 -0
  97. package/src/components/ZoomSlider/styles.ts +57 -0
  98. package/src/constants/index.ts +1 -0
  99. package/src/contexts/GraphStateContext.tsx +19 -0
  100. package/src/contexts/SigmaCustomRenderersContext.ts +20 -0
  101. package/src/helpers/relationsHelpers.ts +9 -0
  102. package/src/hooks/__tests__/useGraphLayout.test.tsx +825 -0
  103. package/src/hooks/__tests__/useGraphLayoutSelector.test.tsx +19 -0
  104. package/src/hooks/__tests__/useSelfRelationLoopsRenderer.test.ts +198 -0
  105. package/src/hooks/__tests__/useSigmaCustomRenderers.test.ts +273 -0
  106. package/src/hooks/__tests__/useTooltipRenderer.test.ts +289 -0
  107. package/src/hooks/useGraphLayout.ts +308 -0
  108. package/src/hooks/useGraphLayoutSelector.ts +19 -0
  109. package/src/hooks/useGraphLoader.ts +279 -0
  110. package/src/hooks/useGraphRightSidePanelElements.tsx +36 -0
  111. package/src/hooks/useGraphState.ts +40 -0
  112. package/src/hooks/useGraphType.ts +32 -0
  113. package/src/hooks/useRelationshipTable.ts +212 -0
  114. package/src/hooks/useRelationshipTableFilters.ts +43 -0
  115. package/src/hooks/useSelectedEntity.ts +89 -0
  116. package/src/hooks/useSelfRelationLoopsRenderer.ts +52 -0
  117. package/src/hooks/useSigmaCustomRenderers.ts +112 -0
  118. package/src/hooks/useTooltipRenderer.ts +80 -0
  119. package/src/index.tsx +37 -0
  120. package/src/rendering/canvas/__tests__/hover.spec.ts +31 -0
  121. package/src/rendering/canvas/__tests__/label.spec.ts +64 -0
  122. package/src/rendering/canvas/__tests__/nodeBackground.spec.ts +99 -0
  123. package/src/rendering/canvas/__tests__/selfRelationLoop.spec.ts +88 -0
  124. package/src/rendering/canvas/__tests__/tooltip.spec.ts +33 -0
  125. package/src/rendering/canvas/hover.ts +13 -0
  126. package/src/rendering/canvas/label.ts +33 -0
  127. package/src/rendering/canvas/nodeBackground.ts +61 -0
  128. package/src/rendering/canvas/selfRelationLoop.ts +108 -0
  129. package/src/rendering/canvas/tooltip.ts +38 -0
  130. package/src/rendering/icons/collapseIcon.inline.svg.ts +6 -0
  131. package/src/rendering/icons/expandIcon.inline.svg.ts +5 -0
  132. package/src/rendering/icons/no_photo.inline.svg.ts +13 -0
  133. package/src/rendering/webgl/edge.arrowHead.ts +87 -0
  134. package/src/rendering/webgl/edge.clamped.ts +246 -0
  135. package/src/rendering/webgl/edge.reversedArrowHead.ts +14 -0
  136. package/src/rendering/webgl/helpers/__tests__/imageHelper.spec.ts +36 -0
  137. package/src/rendering/webgl/helpers/imageHelper.ts +13 -0
  138. package/src/rendering/webgl/image.ts +115 -0
  139. package/src/rendering/webgl/node.border.ts +78 -0
  140. package/src/rendering/webgl/node.buttons.ts +241 -0
  141. package/src/rendering/webgl/node.image.ts +169 -0
  142. package/src/rendering/webgl/shaders/edge.clamped.vert.glsl.ts +55 -0
  143. package/src/rendering/webgl/shaders/node.border.frag.glsl.ts +30 -0
  144. package/src/rendering/webgl/shaders/node.border.vert.glsl.ts +37 -0
  145. package/src/rendering/webgl/shaders/node.buttons.frag.glsl.ts +32 -0
  146. package/src/rendering/webgl/shaders/node.buttons.vert.glsl.ts +49 -0
  147. package/src/rendering/webgl/shaders/node.image.frag.glsl.ts +46 -0
  148. package/src/rendering/webgl/shaders/node.image.vert.glsl.ts +42 -0
  149. package/src/types/graphDataTypes.ts +143 -0
  150. package/src/types/sigmaCustomRenderersTypes.ts +13 -0
  151. package/src/utils/__tests__/graph.spec.ts +152 -0
  152. package/src/utils/__tests__/graphLayout.spec.ts +125 -0
  153. package/src/utils/__tests__/hopsData.spec.ts +456 -0
  154. package/src/utils/__tests__/processResponceToGraph.spec.ts +165 -0
  155. package/src/utils/graph.ts +83 -0
  156. package/src/utils/graphLayout.ts +70 -0
  157. package/src/utils/hopsData.ts +198 -0
  158. package/src/utils/processResponseToGraph.ts +32 -0
  159. package/tsconfig.json +4 -0
  160. package/webpack.config.js +10 -0
  161. package/bundle.js +0 -2
  162. package/bundle.js.LICENSE.txt +0 -54
  163. /package/{5271a9e7b6651c852e93.png → public/5271a9e7b6651c852e93.png} +0 -0
  164. /package/{main.css → public/main.css} +0 -0
@@ -0,0 +1,456 @@
1
+ import {MultiGraph} from 'graphology';
2
+ import {HopsResponse} from '@reltio/mdm-sdk';
3
+ import {mergeHopsData, removeRelationFromHopsData} from '../hopsData';
4
+ import {fillGraphWithHopsResponse} from '../graph';
5
+
6
+ describe('Hops Data utils', () => {
7
+ describe('removeRelationFromHopsData behavior', () => {
8
+ it('should remove relation for simple cases', () => {
9
+ const data: HopsResponse = {
10
+ entities: [
11
+ {uri: 'e1', type: '', traversedRelations: 2},
12
+ {uri: 'e2', type: '', traversedRelations: 2},
13
+ {uri: 'e3', type: '', traversedRelations: 2}
14
+ ],
15
+ relations: [
16
+ {
17
+ uri: 'r1',
18
+ type: '',
19
+ startObject: {
20
+ objectURI: 'e1'
21
+ },
22
+ endObject: {
23
+ objectURI: 'e2'
24
+ }
25
+ },
26
+ {
27
+ uri: 'r2',
28
+ type: '',
29
+ startObject: {
30
+ objectURI: 'e2'
31
+ },
32
+ endObject: {
33
+ objectURI: 'e3'
34
+ }
35
+ },
36
+ {
37
+ uri: 'r3',
38
+ type: '',
39
+ startObject: {
40
+ objectURI: 'e3'
41
+ },
42
+ endObject: {
43
+ objectURI: 'e1'
44
+ }
45
+ }
46
+ ]
47
+ };
48
+ const relationUriToRemove = 'r1';
49
+ const graph = new MultiGraph();
50
+ fillGraphWithHopsResponse(graph, data);
51
+ graph.dropEdge(relationUriToRemove);
52
+
53
+ const mainEntityUri = 'e1';
54
+ expect(removeRelationFromHopsData(mainEntityUri, relationUriToRemove, graph, data)).toEqual({
55
+ updatedData: {
56
+ entities: [
57
+ {...data.entities[0], traversedRelations: 1},
58
+ {...data.entities[1], traversedRelations: 1},
59
+ data.entities[2]
60
+ ],
61
+ relations: [data.relations[1], data.relations[2]]
62
+ },
63
+ removedEntitiesUris: []
64
+ });
65
+ });
66
+
67
+ it('should remove relation and isolated node', () => {
68
+ const data: HopsResponse = {
69
+ entities: [
70
+ {uri: 'e1', type: '', traversedRelations: 1},
71
+ {uri: 'e2', type: '', traversedRelations: 2},
72
+ {uri: 'e3', type: '', traversedRelations: 1}
73
+ ],
74
+ relations: [
75
+ {
76
+ uri: 'r1',
77
+ type: '',
78
+ startObject: {
79
+ objectURI: 'e1'
80
+ },
81
+ endObject: {
82
+ objectURI: 'e2'
83
+ }
84
+ },
85
+ {
86
+ uri: 'r2',
87
+ type: '',
88
+ startObject: {
89
+ objectURI: 'e2'
90
+ },
91
+ endObject: {
92
+ objectURI: 'e3'
93
+ }
94
+ }
95
+ ]
96
+ };
97
+ const relationUriToRemove = 'r2';
98
+ const graph = new MultiGraph();
99
+ fillGraphWithHopsResponse(graph, data);
100
+ graph.dropEdge(relationUriToRemove);
101
+
102
+ const mainEntityUri = 'e1';
103
+ expect(removeRelationFromHopsData(mainEntityUri, relationUriToRemove, graph, data)).toEqual({
104
+ updatedData: {
105
+ entities: [data.entities[0], {...data.entities[1], traversedRelations: 1}],
106
+ relations: [data.relations[0]]
107
+ },
108
+ removedEntitiesUris: ['e3']
109
+ });
110
+ });
111
+
112
+ it('should remove relation and isolated simple subgraph', () => {
113
+ const data: HopsResponse = {
114
+ entities: [
115
+ {uri: 'e1', type: '', traversedRelations: 1},
116
+ {uri: 'e2', type: '', traversedRelations: 2},
117
+ {uri: 'e3', type: '', traversedRelations: 1}
118
+ ],
119
+ relations: [
120
+ {
121
+ uri: 'r1',
122
+ type: '',
123
+ startObject: {
124
+ objectURI: 'e1'
125
+ },
126
+ endObject: {
127
+ objectURI: 'e2'
128
+ }
129
+ },
130
+ {
131
+ uri: 'r2',
132
+ type: '',
133
+ startObject: {
134
+ objectURI: 'e2'
135
+ },
136
+ endObject: {
137
+ objectURI: 'e3'
138
+ }
139
+ }
140
+ ]
141
+ };
142
+ const relationUriToRemove = 'r1';
143
+ const graph = new MultiGraph();
144
+ fillGraphWithHopsResponse(graph, data);
145
+ graph.dropEdge(relationUriToRemove);
146
+
147
+ const mainEntityUri = 'e1';
148
+ expect(removeRelationFromHopsData(mainEntityUri, relationUriToRemove, graph, data)).toEqual({
149
+ updatedData: {
150
+ entities: [{...data.entities[0], traversedRelations: 0}],
151
+ relations: []
152
+ },
153
+ removedEntitiesUris: ['e2', 'e3']
154
+ });
155
+ });
156
+
157
+ it('should remove relation and isolated complex subgraph', () => {
158
+ const data: HopsResponse = {
159
+ entities: [
160
+ {uri: 'e1', type: '', traversedRelations: 1},
161
+ {uri: 'e2', type: '', traversedRelations: 2},
162
+ {uri: 'e3', type: '', traversedRelations: 3},
163
+ {uri: 'e4', type: '', traversedRelations: 3},
164
+ {uri: 'e5', type: '', traversedRelations: 1},
165
+ {uri: 'e6', type: '', traversedRelations: 2}
166
+ ],
167
+ relations: [
168
+ {
169
+ uri: 'r1',
170
+ type: '',
171
+ startObject: {
172
+ objectURI: 'e1'
173
+ },
174
+ endObject: {
175
+ objectURI: 'e2'
176
+ }
177
+ },
178
+ {
179
+ uri: 'r2',
180
+ type: '',
181
+ startObject: {
182
+ objectURI: 'e2'
183
+ },
184
+ endObject: {
185
+ objectURI: 'e3'
186
+ }
187
+ },
188
+ {
189
+ uri: 'r3',
190
+ type: '',
191
+ startObject: {
192
+ objectURI: 'e3'
193
+ },
194
+ endObject: {
195
+ objectURI: 'e4'
196
+ }
197
+ },
198
+ {
199
+ uri: 'r4',
200
+ type: '',
201
+ startObject: {
202
+ objectURI: 'e3'
203
+ },
204
+ endObject: {
205
+ objectURI: 'e6'
206
+ }
207
+ },
208
+ {
209
+ uri: 'r5',
210
+ type: '',
211
+ startObject: {
212
+ objectURI: 'e4'
213
+ },
214
+ endObject: {
215
+ objectURI: 'e6'
216
+ }
217
+ },
218
+ {
219
+ uri: 'r6',
220
+ type: '',
221
+ startObject: {
222
+ objectURI: 'e4'
223
+ },
224
+ endObject: {
225
+ objectURI: 'e5'
226
+ }
227
+ }
228
+ ]
229
+ };
230
+ const relationUriToRemove = 'r2';
231
+ const graph = new MultiGraph();
232
+ fillGraphWithHopsResponse(graph, data);
233
+ graph.dropEdge(relationUriToRemove);
234
+
235
+ const mainEntityUri = 'e1';
236
+ expect(removeRelationFromHopsData(mainEntityUri, relationUriToRemove, graph, data)).toEqual({
237
+ updatedData: {
238
+ entities: [data.entities[0], {...data.entities[1], traversedRelations: 1}],
239
+ relations: [data.relations[0]]
240
+ },
241
+ removedEntitiesUris: ['e3', 'e4', 'e6', 'e5']
242
+ });
243
+ });
244
+
245
+ it('should not remove complex subgraph if it is not isolated', () => {
246
+ const data: HopsResponse = {
247
+ entities: [
248
+ {uri: 'e1', type: '', traversedRelations: 2},
249
+ {uri: 'e2', type: '', traversedRelations: 2},
250
+ {uri: 'e3', type: '', traversedRelations: 3},
251
+ {uri: 'e4', type: '', traversedRelations: 3},
252
+ {uri: 'e5', type: '', traversedRelations: 2},
253
+ {uri: 'e6', type: '', traversedRelations: 2}
254
+ ],
255
+ relations: [
256
+ {
257
+ uri: 'r1',
258
+ type: '',
259
+ startObject: {
260
+ objectURI: 'e1'
261
+ },
262
+ endObject: {
263
+ objectURI: 'e2'
264
+ }
265
+ },
266
+ {
267
+ uri: 'r2',
268
+ type: '',
269
+ startObject: {
270
+ objectURI: 'e2'
271
+ },
272
+ endObject: {
273
+ objectURI: 'e3'
274
+ }
275
+ },
276
+ {
277
+ uri: 'r3',
278
+ type: '',
279
+ startObject: {
280
+ objectURI: 'e3'
281
+ },
282
+ endObject: {
283
+ objectURI: 'e4'
284
+ }
285
+ },
286
+ {
287
+ uri: 'r4',
288
+ type: '',
289
+ startObject: {
290
+ objectURI: 'e3'
291
+ },
292
+ endObject: {
293
+ objectURI: 'e6'
294
+ }
295
+ },
296
+ {
297
+ uri: 'r5',
298
+ type: '',
299
+ startObject: {
300
+ objectURI: 'e4'
301
+ },
302
+ endObject: {
303
+ objectURI: 'e6'
304
+ }
305
+ },
306
+ {
307
+ uri: 'r6',
308
+ type: '',
309
+ startObject: {
310
+ objectURI: 'e4'
311
+ },
312
+ endObject: {
313
+ objectURI: 'e5'
314
+ }
315
+ },
316
+ {
317
+ // additional path to e1
318
+ uri: 'r7',
319
+ type: '',
320
+ startObject: {
321
+ objectURI: 'e5'
322
+ },
323
+ endObject: {
324
+ objectURI: 'e1'
325
+ }
326
+ }
327
+ ]
328
+ };
329
+ const relationUriToRemove = 'r2';
330
+ const graph = new MultiGraph();
331
+ fillGraphWithHopsResponse(graph, data);
332
+ graph.dropEdge(relationUriToRemove);
333
+
334
+ const mainEntityUri = 'e1';
335
+ expect(removeRelationFromHopsData(mainEntityUri, relationUriToRemove, graph, data)).toEqual({
336
+ updatedData: {
337
+ entities: [
338
+ data.entities[0],
339
+ {...data.entities[1], traversedRelations: 1},
340
+ {...data.entities[2], traversedRelations: 2},
341
+ data.entities[3],
342
+ data.entities[4],
343
+ data.entities[5]
344
+ ],
345
+ relations: data.relations.filter((relation) => relation.uri !== relationUriToRemove)
346
+ },
347
+ removedEntitiesUris: []
348
+ });
349
+ });
350
+ });
351
+
352
+ describe('mergeHopsData behavior', () => {
353
+ it('should merge data', () => {
354
+ const data: HopsResponse = {
355
+ entities: [
356
+ {uri: 'e1', type: '', traversedRelations: 2, untraversedRelations: 0},
357
+ {uri: 'e2', type: '', traversedRelations: 2, untraversedRelations: 1},
358
+ {uri: 'e3', type: '', traversedRelations: 2, untraversedRelations: 2}
359
+ ],
360
+ relations: [
361
+ {
362
+ uri: 'r1',
363
+ type: '',
364
+ startObject: {
365
+ objectURI: 'e1'
366
+ },
367
+ endObject: {
368
+ objectURI: 'e2'
369
+ }
370
+ },
371
+ {
372
+ uri: 'r2',
373
+ type: '',
374
+ startObject: {
375
+ objectURI: 'e2'
376
+ },
377
+ endObject: {
378
+ objectURI: 'e3'
379
+ }
380
+ },
381
+ {
382
+ uri: 'r3',
383
+ type: '',
384
+ startObject: {
385
+ objectURI: 'e3'
386
+ },
387
+ endObject: {
388
+ objectURI: 'e1'
389
+ }
390
+ }
391
+ ]
392
+ };
393
+
394
+ const newData: HopsResponse = {
395
+ entities: [
396
+ {uri: 'e2', type: '', traversedRelations: 3, untraversedRelations: 0},
397
+ {uri: 'e4', type: '', traversedRelations: 1, untraversedRelations: 2},
398
+ {uri: 'e1', type: '', traversedRelations: 1, untraversedRelations: 1}
399
+ ],
400
+ relations: [
401
+ {
402
+ uri: 'r1',
403
+ type: '',
404
+ startObject: {
405
+ objectURI: 'e1'
406
+ },
407
+ endObject: {
408
+ objectURI: 'e2'
409
+ }
410
+ },
411
+ {
412
+ uri: 'r2',
413
+ type: '',
414
+ startObject: {
415
+ objectURI: 'e2'
416
+ },
417
+ endObject: {
418
+ objectURI: 'e3'
419
+ }
420
+ },
421
+ {
422
+ uri: 'r4',
423
+ type: '',
424
+ startObject: {
425
+ objectURI: 'e2'
426
+ },
427
+ endObject: {
428
+ objectURI: 'e4'
429
+ }
430
+ }
431
+ ]
432
+ };
433
+ expect(mergeHopsData(data, newData, 'e2')).toEqual({
434
+ entities: [
435
+ data.entities[0],
436
+ {...data.entities[1], traversedRelations: 3, untraversedRelations: 0},
437
+ data.entities[2],
438
+ {uri: 'e4', type: '', traversedRelations: 1, untraversedRelations: 2}
439
+ ],
440
+ relations: [
441
+ ...data.relations,
442
+ {
443
+ uri: 'r4',
444
+ type: '',
445
+ startObject: {
446
+ objectURI: 'e2'
447
+ },
448
+ endObject: {
449
+ objectURI: 'e4'
450
+ }
451
+ }
452
+ ]
453
+ });
454
+ });
455
+ });
456
+ });
@@ -0,0 +1,165 @@
1
+ import processResponseToGraph from '../processResponseToGraph';
2
+ import {RelationTypeDirection} from '@reltio/mdm-sdk';
3
+
4
+ const response = {
5
+ entities: [
6
+ {
7
+ uri: 'entities/369r4MS',
8
+ type: 'configuration/entityTypes/Employee',
9
+ label: 'Eugeny Gorshkov',
10
+ secondaryLabel: '',
11
+ traversedRelations: 0,
12
+ untraversedRelations: 5
13
+ },
14
+ {
15
+ uri: 'entities/369uzJA',
16
+ type: 'configuration/entityTypes/Employee',
17
+ label: 'Oleg Mikhailov',
18
+ secondaryLabel: '',
19
+ traversedRelations: 1,
20
+ untraversedRelations: 0
21
+ },
22
+ {
23
+ uri: 'entities/HAWcyp1',
24
+ type: 'configuration/entityTypes/Course',
25
+ label: 'ROP-0112 Data Security',
26
+ secondaryLabel: '',
27
+ traversedRelations: 2,
28
+ untraversedRelations: 5
29
+ }
30
+ ],
31
+ relations: [
32
+ {
33
+ uri: 'relations/9cdak6R',
34
+ type: 'configuration/relationTypes/ContactToCourse',
35
+ startObject: {
36
+ directionalLabel: '',
37
+ objectURI: 'entities/HAWcyp1'
38
+ },
39
+ endObject: {
40
+ directionalLabel: '',
41
+ objectURI: 'entities/369uzJA'
42
+ },
43
+ direction: RelationTypeDirection.directed
44
+ },
45
+ {
46
+ uri: 'relations/0L81as4',
47
+ type: 'configuration/relationTypes/ContactToCourse',
48
+ startObject: {
49
+ directionalLabel: '',
50
+ objectURI: 'entities/369uzJA'
51
+ },
52
+ endObject: {
53
+ directionalLabel: '',
54
+ objectURI: 'entities/HAWZkUt'
55
+ },
56
+ direction: RelationTypeDirection.directed
57
+ },
58
+ {
59
+ uri: 'relations/0C1hBCo',
60
+ type: 'configuration/relationTypes/ContactToCourse',
61
+ startObject: {
62
+ directionalLabel: '',
63
+ objectURI: 'entities/HAWcyp1'
64
+ },
65
+ endObject: {
66
+ directionalLabel: '',
67
+ objectURI: 'entities/369uzJA'
68
+ },
69
+ direction: RelationTypeDirection.directed
70
+ },
71
+ {
72
+ uri: 'relations/WkSntXP',
73
+ type: 'configuration/relationTypes/ContactToCourse',
74
+ startObject: {
75
+ directionalLabel: '',
76
+ objectURI: 'entities/369uzJA'
77
+ },
78
+ endObject: {
79
+ directionalLabel: '',
80
+ objectURI: 'entities/369r4MS'
81
+ },
82
+ direction: RelationTypeDirection.directed
83
+ },
84
+ {
85
+ uri: 'relations/WdfntXP',
86
+ type: 'configuration/relationTypes/ContactToCourse',
87
+ startObject: {
88
+ directionalLabel: '',
89
+ objectURI: 'entities/369r4MS'
90
+ },
91
+ endObject: {
92
+ directionalLabel: '',
93
+ objectURI: 'entities/369uzJA'
94
+ },
95
+ direction: RelationTypeDirection.bidirectional
96
+ }
97
+ ]
98
+ };
99
+
100
+ const expectedGraph = {
101
+ nodes: [
102
+ {
103
+ id: 'entities/369r4MS',
104
+ name: 'Eugeny Gorshkov',
105
+ entityTypeUri: 'configuration/entityTypes/Employee',
106
+ traversedRelationsCount: 0,
107
+ untraversedRelationsCount: 5
108
+ },
109
+ {
110
+ id: 'entities/369uzJA',
111
+ name: 'Oleg Mikhailov',
112
+ entityTypeUri: 'configuration/entityTypes/Employee',
113
+ traversedRelationsCount: 1,
114
+ untraversedRelationsCount: 0
115
+ },
116
+ {
117
+ id: 'entities/HAWcyp1',
118
+ name: 'ROP-0112 Data Security',
119
+ entityTypeUri: 'configuration/entityTypes/Course',
120
+ traversedRelationsCount: 2,
121
+ untraversedRelationsCount: 5
122
+ }
123
+ ],
124
+ edges: [
125
+ {
126
+ from: 'entities/HAWcyp1',
127
+ to: 'entities/369uzJA',
128
+ key: 'relations/9cdak6R',
129
+ relationTypeUri: 'configuration/relationTypes/ContactToCourse',
130
+ direction: RelationTypeDirection.directed
131
+ },
132
+ {
133
+ from: 'entities/HAWcyp1',
134
+ to: 'entities/369uzJA',
135
+ key: 'relations/0C1hBCo',
136
+ relationTypeUri: 'configuration/relationTypes/ContactToCourse',
137
+ direction: RelationTypeDirection.directed
138
+ },
139
+ {
140
+ from: 'entities/369uzJA',
141
+ to: 'entities/369r4MS',
142
+ key: 'relations/WkSntXP',
143
+ relationTypeUri: 'configuration/relationTypes/ContactToCourse',
144
+ direction: RelationTypeDirection.directed
145
+ },
146
+ {
147
+ from: 'entities/369r4MS',
148
+ to: 'entities/369uzJA',
149
+ key: 'relations/WdfntXP',
150
+ relationTypeUri: 'configuration/relationTypes/ContactToCourse',
151
+ direction: RelationTypeDirection.bidirectional
152
+ }
153
+ ]
154
+ };
155
+
156
+ describe('Graph processResponseToGraph behavior', () => {
157
+ it('should process response to graph data format', () => {
158
+ const graph = processResponseToGraph(response);
159
+ expect(graph).toEqual(expectedGraph);
160
+ });
161
+ it('should process response without relations to graph data format', () => {
162
+ const graph = processResponseToGraph({entities: response.entities});
163
+ expect(graph).toEqual({nodes: expectedGraph.nodes, edges: []});
164
+ });
165
+ });
@@ -0,0 +1,83 @@
1
+ import Graph from 'graphology';
2
+ import {toUndirected} from 'graphology-operators';
3
+ import {bidirectional} from 'graphology-shortest-path';
4
+ import {uniq} from 'ramda';
5
+ import {HopsResponse, getLabel} from '@reltio/mdm-sdk';
6
+ import processResponseToGraph from './processResponseToGraph';
7
+
8
+ export const fillGraphWithHopsResponse = (graph: Graph, data: HopsResponse) => {
9
+ const graphologyData = processResponseToGraph(data);
10
+ graphologyData.nodes.forEach((node) => {
11
+ if (!graph.hasNode(node.id)) {
12
+ graph.addNode(node.id, {
13
+ label: getLabel(node.name),
14
+ entityTypeUri: node.entityTypeUri,
15
+ traversedRelationsCount: node.traversedRelationsCount,
16
+ untraversedRelationsCount: node.untraversedRelationsCount,
17
+ x: 1,
18
+ y: 1
19
+ });
20
+ }
21
+ });
22
+ graphologyData.edges.forEach((edge) => {
23
+ const isSelfRelation = edge.from === edge.to;
24
+
25
+ if (!graph.hasEdge(edge.key)) {
26
+ graph.addEdgeWithKey(edge.key, edge.from, edge.to, {
27
+ size: 1,
28
+ color: 'rgba(0, 0, 0, 0.2)',
29
+ forceLabel: isSelfRelation,
30
+ loop: isSelfRelation,
31
+ relationTypeUri: edge.relationTypeUri,
32
+ direction: edge.direction
33
+ });
34
+ }
35
+ });
36
+ };
37
+
38
+ export const removeNodesFromGraph = (graph: Graph, nodesIdsToRemove?: string[]) => {
39
+ (nodesIdsToRemove || []).forEach((id) => {
40
+ graph.dropNode(id);
41
+ });
42
+ };
43
+
44
+ const getIsolatedNodeId = (undirectedGraph: Graph, firstNode: string, secondaryNode: string) => {
45
+ return !bidirectional(undirectedGraph, firstNode, secondaryNode) ? secondaryNode : null;
46
+ };
47
+
48
+ const findSubgraphNodes = (nodeId: string, graph: Graph, foundNodes: string[] = []): string[] => {
49
+ const nodes = graph.neighbors(nodeId).filter((node) => !foundNodes.includes(node));
50
+ foundNodes.push(...nodes);
51
+ nodes.forEach((neighborNodeId) => findSubgraphNodes(neighborNodeId, graph, foundNodes));
52
+ return foundNodes;
53
+ };
54
+
55
+ export const getIsolatedNodes = (entityUri: string, mainNode: string, nodes: string[], graph: Graph) => {
56
+ const undirectedGraph = toUndirected(graph);
57
+
58
+ const dropEdge = (firstNode: string, secondNode: string) => {
59
+ const edges = undirectedGraph.filterEdges(firstNode, secondNode, (x) => !!x);
60
+ edges.forEach((edge) => undirectedGraph.dropEdge(edge));
61
+ };
62
+
63
+ nodes.forEach((node) => {
64
+ dropEdge(mainNode, node);
65
+ undirectedGraph.forEachNeighbor(node, (neighborNode) => {
66
+ dropEdge(node, neighborNode);
67
+ });
68
+ });
69
+
70
+ const isolatedNodes = [];
71
+ undirectedGraph.nodes().forEach((node) => {
72
+ if (getIsolatedNodeId(undirectedGraph, entityUri, node)) {
73
+ isolatedNodes.push(node);
74
+ }
75
+ });
76
+
77
+ return uniq(
78
+ isolatedNodes.reduce(
79
+ (nodes, isolatedNode) => findSubgraphNodes(isolatedNode, undirectedGraph, nodes),
80
+ [...isolatedNodes]
81
+ )
82
+ );
83
+ };