@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,230 @@
1
+ import {GraphLayout} from '@reltio/mdm-sdk';
2
+ import {
3
+ calculateXPos,
4
+ calculateYPos,
5
+ getAngleOfRotation,
6
+ getMaxLvlSize,
7
+ getMaxQuantityNodesOnOneLvl,
8
+ isSimpleGraph
9
+ } from '../calculations';
10
+
11
+ describe('calculations behavior', () => {
12
+ it('calculateXPos should work correctly', () => {
13
+ expect(
14
+ calculateXPos({
15
+ quantityAtLvl: 10,
16
+ posAtLvl: 2,
17
+ max: 10,
18
+ isEvenRow: true,
19
+ layout: GraphLayout.HORIZONTAL_LR,
20
+ shouldUseCheckboardPattern: true
21
+ })
22
+ ).toBe(25);
23
+
24
+ expect(
25
+ calculateXPos({
26
+ quantityAtLvl: 10,
27
+ posAtLvl: 4,
28
+ max: 10,
29
+ isEvenRow: true,
30
+ layout: GraphLayout.HORIZONTAL_LR,
31
+ shouldUseCheckboardPattern: true
32
+ })
33
+ ).toBe(45);
34
+
35
+ expect(
36
+ calculateXPos({
37
+ quantityAtLvl: 10,
38
+ posAtLvl: 2,
39
+ max: 10,
40
+ isEvenRow: false,
41
+ layout: GraphLayout.HORIZONTAL_LR,
42
+ shouldUseCheckboardPattern: true
43
+ })
44
+ ).toBe(20);
45
+
46
+ expect(
47
+ calculateXPos({
48
+ quantityAtLvl: 10,
49
+ posAtLvl: 5,
50
+ max: 10,
51
+ isEvenRow: true,
52
+ layout: GraphLayout.VERTICAL_TB,
53
+ shouldUseCheckboardPattern: true
54
+ })
55
+ ).toBe(50);
56
+
57
+ expect(
58
+ calculateXPos({
59
+ quantityAtLvl: 10,
60
+ posAtLvl: 7,
61
+ max: 10,
62
+ isEvenRow: true,
63
+ layout: GraphLayout.HORIZONTAL_LR,
64
+ shouldUseCheckboardPattern: false
65
+ })
66
+ ).toBe(70);
67
+
68
+ expect(
69
+ calculateXPos({
70
+ quantityAtLvl: 1,
71
+ posAtLvl: 0,
72
+ max: 10,
73
+ isEvenRow: true,
74
+ layout: GraphLayout.HORIZONTAL_LR,
75
+ shouldUseCheckboardPattern: true
76
+ })
77
+ ).toBe(45);
78
+
79
+ expect(
80
+ calculateXPos({
81
+ quantityAtLvl: 1,
82
+ posAtLvl: 0,
83
+ max: 5,
84
+ isEvenRow: true,
85
+ layout: GraphLayout.HORIZONTAL_LR,
86
+ shouldUseCheckboardPattern: true
87
+ })
88
+ ).toBe(20);
89
+
90
+ expect(
91
+ calculateXPos({
92
+ quantityAtLvl: 5,
93
+ posAtLvl: 3,
94
+ max: 10,
95
+ isEvenRow: true,
96
+ layout: GraphLayout.HORIZONTAL_LR,
97
+ shouldUseCheckboardPattern: true
98
+ })
99
+ ).toBe(60);
100
+
101
+ expect(
102
+ calculateXPos({
103
+ quantityAtLvl: 4,
104
+ posAtLvl: 2,
105
+ max: 8,
106
+ isEvenRow: true,
107
+ layout: GraphLayout.HORIZONTAL_LR,
108
+ shouldUseCheckboardPattern: true
109
+ })
110
+ ).toBe(42);
111
+ });
112
+
113
+ it('calculateYPos should work correctly', () => {
114
+ expect(
115
+ calculateYPos({
116
+ quantityAtLvl: 10,
117
+ rowNumber: 5,
118
+ isEvenItem: true,
119
+ layout: GraphLayout.VERTICAL_TB,
120
+ shouldUseCheckboardPattern: true
121
+ })
122
+ ).toBe(55);
123
+
124
+ expect(
125
+ calculateYPos({
126
+ quantityAtLvl: 10,
127
+ rowNumber: 8,
128
+ isEvenItem: true,
129
+ layout: GraphLayout.VERTICAL_TB,
130
+ shouldUseCheckboardPattern: true
131
+ })
132
+ ).toBe(85);
133
+
134
+ expect(
135
+ calculateYPos({
136
+ quantityAtLvl: 10,
137
+ rowNumber: 5,
138
+ isEvenItem: true,
139
+ layout: GraphLayout.VERTICAL_TB,
140
+ shouldUseCheckboardPattern: false
141
+ })
142
+ ).toBe(50);
143
+
144
+ expect(
145
+ calculateYPos({
146
+ quantityAtLvl: 10,
147
+ rowNumber: 1,
148
+ isEvenItem: true,
149
+ layout: GraphLayout.HORIZONTAL_LR,
150
+ shouldUseCheckboardPattern: true
151
+ })
152
+ ).toBe(10);
153
+
154
+ expect(
155
+ calculateYPos({
156
+ quantityAtLvl: 10,
157
+ rowNumber: 3,
158
+ isEvenItem: false,
159
+ layout: GraphLayout.VERTICAL_TB,
160
+ shouldUseCheckboardPattern: true
161
+ })
162
+ ).toBe(30);
163
+
164
+ expect(
165
+ calculateYPos({
166
+ quantityAtLvl: 1,
167
+ rowNumber: 0,
168
+ isEvenItem: true,
169
+ layout: GraphLayout.VERTICAL_TB,
170
+ shouldUseCheckboardPattern: true
171
+ })
172
+ ).toBe(0);
173
+ });
174
+
175
+ describe('getAngleOfRotation', () => {
176
+ it('should return correctly angle for Horizontal layout', () => {
177
+ expect(getAngleOfRotation(GraphLayout.HORIZONTAL_LR)).toBe(270);
178
+ });
179
+
180
+ it('should return correctly angle for Vertical layout', () => {
181
+ expect(getAngleOfRotation(GraphLayout.VERTICAL_TB)).toBe(180);
182
+ });
183
+ });
184
+
185
+ describe('getMaxLvlSize', () => {
186
+ it('should return max level size correctly', () => {
187
+ expect(getMaxLvlSize([['node1'], ['node2', 'node3', 'node4'], ['node5', 'node6']])).toBe(3);
188
+ expect(getMaxLvlSize([['node1'], ['node2', 'node3'], ['node4', 'node5']])).toBe(2);
189
+ expect(getMaxLvlSize([['node1'], ['node2', 'node3'], ['node4', 'node5', 'node6', 'node7']])).toBe(4);
190
+ });
191
+ });
192
+
193
+ describe('isSimpleGraph', () => {
194
+ it('should return true for lengths shorter than 100', () => {
195
+ expect(isSimpleGraph(50)).toBe(true);
196
+ expect(isSimpleGraph(1)).toBe(true);
197
+ expect(isSimpleGraph(80)).toBe(true);
198
+ expect(isSimpleGraph(99)).toBe(true);
199
+ });
200
+
201
+ it('should return false for lengths longer than 100', () => {
202
+ expect(isSimpleGraph(100)).toBe(false);
203
+ expect(isSimpleGraph(150)).toBe(false);
204
+ expect(isSimpleGraph(200)).toBe(false);
205
+ expect(isSimpleGraph(1000)).toBe(false);
206
+ });
207
+ });
208
+
209
+ describe('getMaxQuantityNodesOnOneLvl', () => {
210
+ it('should return default max quantity nodes at level for nodesLength shorter than 100', () => {
211
+ expect(getMaxQuantityNodesOnOneLvl(10, GraphLayout.HORIZONTAL_LR)).toBe(10);
212
+ expect(getMaxQuantityNodesOnOneLvl(50, GraphLayout.VERTICAL_TB)).toBe(10);
213
+ expect(getMaxQuantityNodesOnOneLvl(80, GraphLayout.HORIZONTAL_LR)).toBe(10);
214
+ });
215
+
216
+ it('should calculate max quantity nodes at level for nodesLength longer than 100 and Horizontal layout', () => {
217
+ expect(getMaxQuantityNodesOnOneLvl(120, GraphLayout.HORIZONTAL_LR)).toBe(8);
218
+ expect(getMaxQuantityNodesOnOneLvl(200, GraphLayout.HORIZONTAL_LR)).toBe(10);
219
+ expect(getMaxQuantityNodesOnOneLvl(500, GraphLayout.HORIZONTAL_LR)).toBe(16);
220
+ expect(getMaxQuantityNodesOnOneLvl(1000, GraphLayout.HORIZONTAL_LR)).toBe(22);
221
+ });
222
+
223
+ it('should calculate max quantity nodes at level for nodesLength longer than 100 and Vertical layout', () => {
224
+ expect(getMaxQuantityNodesOnOneLvl(120, GraphLayout.VERTICAL_TB)).toBe(16);
225
+ expect(getMaxQuantityNodesOnOneLvl(200, GraphLayout.VERTICAL_TB)).toBe(21);
226
+ expect(getMaxQuantityNodesOnOneLvl(500, GraphLayout.VERTICAL_TB)).toBe(34);
227
+ expect(getMaxQuantityNodesOnOneLvl(1000, GraphLayout.VERTICAL_TB)).toBe(47);
228
+ });
229
+ });
230
+ });
@@ -0,0 +1,109 @@
1
+ import Graph from 'graphology';
2
+ import {GraphologyGraphData, Node, Edge, NodesHierarchy} from '../../types/graphDataTypes';
3
+
4
+ const getFirstLvlNodes = (edgesWithoutLoops: Edge[], nodes: Node[], selectedNode: string): Set<string> => {
5
+ const firstLvlNodesIds = new Set<string>();
6
+ nodes.forEach((node) => {
7
+ if (!edgesWithoutLoops.some((edge) => edge.to === node.id)) {
8
+ firstLvlNodesIds.add(node.id);
9
+ }
10
+ });
11
+ if (!firstLvlNodesIds.size) {
12
+ firstLvlNodesIds.add(selectedNode);
13
+ }
14
+ return firstLvlNodesIds;
15
+ };
16
+
17
+ const canFindChildNodes = (nodesIds: Set<string>, edgesWithoutLoops: Edge[], processedNodes) => {
18
+ const children = new Set<string>();
19
+ nodesIds.forEach((nodeId) => {
20
+ edgesWithoutLoops.forEach((edge) => {
21
+ if (edge.from === nodeId && !processedNodes.has(edge.to)) {
22
+ children.add(edge.to);
23
+ }
24
+ });
25
+ });
26
+ return !!children.size;
27
+ };
28
+
29
+ const findChildNodeIds = (
30
+ parentNodes: Set<string>,
31
+ nodesArr: NodesHierarchy,
32
+ processedNodes: Set<string>,
33
+ edgesWithoutLoops: Edge[]
34
+ ): NodesHierarchy => {
35
+ const currentLvlNodeIds = new Set<string>();
36
+ if (!nodesArr.length) {
37
+ nodesArr.push(Array.from(parentNodes));
38
+ }
39
+ parentNodes.forEach((nodeId) => {
40
+ processedNodes.add(nodeId);
41
+ edgesWithoutLoops.forEach((edge) => {
42
+ if (edge.from === nodeId && !parentNodes.has(edge.to) && !processedNodes.has(edge.to)) {
43
+ currentLvlNodeIds.add(edge.to);
44
+ }
45
+ });
46
+ });
47
+ if (currentLvlNodeIds.size) {
48
+ nodesArr.push(Array.from(currentLvlNodeIds));
49
+ }
50
+
51
+ if (canFindChildNodes(currentLvlNodeIds, edgesWithoutLoops, processedNodes)) {
52
+ return findChildNodeIds(currentLvlNodeIds, nodesArr, processedNodes, edgesWithoutLoops);
53
+ } else return nodesArr;
54
+ };
55
+
56
+ const splitLongLevels = (
57
+ nodes: string[],
58
+ finalHierarchyNodesArr: NodesHierarchy,
59
+ nodesHierarchy: NodesHierarchy,
60
+ level: number,
61
+ maxQuantityNodesOnOneLvl: number
62
+ ): NodesHierarchy => {
63
+ if (nodes.length <= maxQuantityNodesOnOneLvl) {
64
+ finalHierarchyNodesArr[level] = [...nodes];
65
+ }
66
+ if (nodes.length > maxQuantityNodesOnOneLvl) {
67
+ const extraNodes = nodes.slice(maxQuantityNodesOnOneLvl);
68
+ const remainingNodes = nodes.slice(0, maxQuantityNodesOnOneLvl);
69
+
70
+ finalHierarchyNodesArr[level] = remainingNodes;
71
+ finalHierarchyNodesArr[level + 1] = nodesHierarchy[level + 1]
72
+ ? [...nodesHierarchy[level + 1], ...extraNodes]
73
+ : extraNodes;
74
+ }
75
+ if (finalHierarchyNodesArr[level + 1] || nodesHierarchy[level + 1]) {
76
+ level++;
77
+ const nodes = finalHierarchyNodesArr[level] || nodesHierarchy[level];
78
+ return splitLongLevels(nodes, finalHierarchyNodesArr, nodesHierarchy, level, maxQuantityNodesOnOneLvl);
79
+ } else {
80
+ return finalHierarchyNodesArr;
81
+ }
82
+ };
83
+
84
+ export const buildHierarchyNodes = (
85
+ graphData: GraphologyGraphData,
86
+ selectedNode: string,
87
+ maxQuantityNodesOnOneLvl = 10
88
+ ): NodesHierarchy => {
89
+ const nodes = graphData.nodes;
90
+ const edgesWithoutLoops = graphData.edges.filter((edge) => edge.from !== edge.to);
91
+ const firstLvlNodeIds = getFirstLvlNodes(edgesWithoutLoops, nodes, selectedNode);
92
+
93
+ const nodesHierarchy = findChildNodeIds(firstLvlNodeIds, [], new Set<string>(), edgesWithoutLoops);
94
+ const finalHierarchyNodesArr = splitLongLevels(nodesHierarchy[0], [], nodesHierarchy, 0, maxQuantityNodesOnOneLvl);
95
+
96
+ return finalHierarchyNodesArr;
97
+ };
98
+
99
+ export const extractDataFromGraph = (graph: Graph): GraphologyGraphData => {
100
+ const nodes = graph.nodes().map((id) => ({id, name: ''} as Node));
101
+ const edges = graph.mapEdges((edge, attributes, source, target) => ({
102
+ from: source,
103
+ to: target,
104
+ key: edge,
105
+ relationTypeUri: attributes.relationTypeUri,
106
+ direction: attributes.direction
107
+ }));
108
+ return {nodes, edges};
109
+ };
@@ -0,0 +1,86 @@
1
+ import {GraphLayout} from '@reltio/mdm-sdk';
2
+ import {NodesHierarchy} from '../../types/graphDataTypes';
3
+
4
+ const X_MARGIN = 10;
5
+ const Y_MARGIN = 10;
6
+
7
+ type CalculateYPosProps = {
8
+ quantityAtLvl: number;
9
+ rowNumber: number;
10
+ isEvenItem: boolean;
11
+ layout: GraphLayout;
12
+ shouldUseCheckboardPattern: boolean;
13
+ };
14
+
15
+ export const calculateYPos = ({
16
+ quantityAtLvl,
17
+ rowNumber,
18
+ isEvenItem,
19
+ layout,
20
+ shouldUseCheckboardPattern
21
+ }: CalculateYPosProps) => {
22
+ const isVerticalHierarchy = layout === GraphLayout.VERTICAL_TB;
23
+ const hasSingleNodeAtLvl = quantityAtLvl === 1;
24
+ return shouldUseCheckboardPattern && isVerticalHierarchy && isEvenItem && !hasSingleNodeAtLvl
25
+ ? rowNumber * Y_MARGIN + Y_MARGIN / 2
26
+ : rowNumber * Y_MARGIN;
27
+ };
28
+
29
+ type CalculateXPosProps = {
30
+ quantityAtLvl: number;
31
+ posAtLvl: number;
32
+ max: number;
33
+ isEvenRow: boolean;
34
+ layout: GraphLayout;
35
+ shouldUseCheckboardPattern: boolean;
36
+ };
37
+
38
+ export const calculateXPos = ({
39
+ quantityAtLvl,
40
+ posAtLvl,
41
+ max,
42
+ isEvenRow,
43
+ layout,
44
+ shouldUseCheckboardPattern
45
+ }: CalculateXPosProps) => {
46
+ const isHorizontalHierarchy = layout === GraphLayout.HORIZONTAL_LR;
47
+ const hasSingleNodeAtLvl = quantityAtLvl === 1;
48
+ const hasMaxNodesAtLvl = quantityAtLvl === max;
49
+
50
+ if (hasMaxNodesAtLvl) {
51
+ return shouldUseCheckboardPattern && isEvenRow && isHorizontalHierarchy
52
+ ? posAtLvl * X_MARGIN + X_MARGIN / 2
53
+ : posAtLvl * X_MARGIN;
54
+ }
55
+
56
+ if (hasSingleNodeAtLvl) {
57
+ return ((max - 1) * X_MARGIN) / 2;
58
+ }
59
+
60
+ return (((max - 1) * X_MARGIN) / (quantityAtLvl + 1)) * (posAtLvl + 1);
61
+ };
62
+
63
+ export const getAngleOfRotation = (layout: GraphLayout) => {
64
+ switch (layout) {
65
+ case GraphLayout.VERTICAL_TB:
66
+ return 180;
67
+ case GraphLayout.HORIZONTAL_LR:
68
+ return 270;
69
+ }
70
+ };
71
+
72
+ export const getMaxLvlSize = (hierarchyNodes: NodesHierarchy) => {
73
+ const sizes = hierarchyNodes.map((nodes) => nodes.length);
74
+ return Math.max(...sizes);
75
+ };
76
+
77
+ export const isSimpleGraph = (nodesLength: number) => nodesLength < 100;
78
+
79
+ export const getMaxQuantityNodesOnOneLvl = (nodesLength: number, layout: GraphLayout) => {
80
+ if (isSimpleGraph(nodesLength)) {
81
+ return 10;
82
+ }
83
+
84
+ const multiplier = layout === GraphLayout.VERTICAL_TB ? 1.5 : 0.7;
85
+ return Math.round(Math.sqrt(nodesLength) * multiplier);
86
+ };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import {pick} from 'ramda';
3
+ import {Entity} from '@reltio/mdm-sdk';
4
+ import {AttributesView, withContext, LinearLoadIndicator} from '@reltio/components';
5
+ import {GraphStateContext} from '../../contexts/GraphStateContext';
6
+
7
+ import {useStyles} from './styles';
8
+ import i18n from 'ui-i18n';
9
+
10
+ type Props = {
11
+ selectedEntity?: Entity;
12
+ selectedEntityLoading?: boolean;
13
+ };
14
+
15
+ const RightPanelEntityDetails = ({selectedEntity, selectedEntityLoading}: Props) => {
16
+ const styles = useStyles();
17
+ return (
18
+ <div className={styles.wrapper}>
19
+ {selectedEntityLoading && <LinearLoadIndicator />}
20
+ <AttributesView
21
+ entity={selectedEntity}
22
+ caption={i18n.text('Entity details')}
23
+ className={styles.noShadowBlock}
24
+ />
25
+ </div>
26
+ );
27
+ };
28
+
29
+ export default withContext(
30
+ GraphStateContext,
31
+ pick(['selectedEntity', 'selectedEntityLoading']),
32
+ RightPanelEntityDetails
33
+ );
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import {mount} from 'enzyme';
3
+ import {AttributesView} from '@reltio/components';
4
+
5
+ import RightPanelEntityDetails from '../RightPanelEntityDetails';
6
+ import {GraphStateContext} from '../../../contexts/GraphStateContext';
7
+ import {GraphState} from '../../../types/graphDataTypes';
8
+
9
+ jest.mock('@reltio/components', () => ({
10
+ ...jest.requireActual<Record<string, unknown>>('@reltio/components'),
11
+ AttributesView: () => null
12
+ }));
13
+
14
+ const setUp = ({selectedEntity = null, selectedEntityLoading = false} = {}) =>
15
+ mount(
16
+ <GraphStateContext.Provider value={{selectedEntity, selectedEntityLoading} as GraphState}>
17
+ <RightPanelEntityDetails />
18
+ </GraphStateContext.Provider>
19
+ );
20
+
21
+ describe('RightPanelEntityDetails tests', () => {
22
+ it('should render AttributesView with selectedEntity from context', () => {
23
+ const selectedEntity = {uri: 'uri1'};
24
+ const component = setUp({selectedEntity});
25
+ const attributesView = component.find(AttributesView);
26
+ expect(attributesView).toHaveLength(1);
27
+ expect(attributesView.prop('entity')).toBe(selectedEntity);
28
+ expect(attributesView.prop('caption')).toBe('Entity details');
29
+ expect(attributesView.prop('className')).toContain('noShadowBlock');
30
+ });
31
+
32
+ it('should render empty AttributesView while entity is loading', () => {
33
+ const component = setUp({selectedEntityLoading: true});
34
+ const attributesView = component.find(AttributesView);
35
+ expect(attributesView).toHaveLength(1);
36
+ expect(attributesView.prop('entity')).toBe(null);
37
+ expect(attributesView.prop('caption')).toBe('Entity details');
38
+ });
39
+ });
@@ -0,0 +1,12 @@
1
+ import {makeStyles} from '@mui/styles';
2
+
3
+ export const useStyles = makeStyles({
4
+ noShadowBlock: {
5
+ boxShadow: 'none'
6
+ },
7
+ wrapper: {
8
+ position: 'relative',
9
+ paddingRight: '1px',
10
+ overflow: 'auto'
11
+ }
12
+ });
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import {pick} from 'ramda';
3
+ import {useSelector} from 'react-redux';
4
+ import {Entity, getEntityUriForLink} from '@reltio/mdm-sdk';
5
+ import {EntityUriLink, ProfileBand, withContext} from '@reltio/components';
6
+ import mdmModule from '@reltio/mdm-module';
7
+ import {GraphStateContext} from '../../contexts/GraphStateContext';
8
+ import {useStyles} from './styles';
9
+
10
+ type Props = {
11
+ selectedEntity?: Entity;
12
+ };
13
+
14
+ const RightPanelProfileBand = ({selectedEntity}: Props) => {
15
+ const styles = useStyles();
16
+
17
+ const entityUri = useSelector(mdmModule.selectors.getEntityUri);
18
+ const selectedEntityUri = selectedEntity?.uri;
19
+
20
+ const renderLabel = (label: string) => {
21
+ if (entityUri === selectedEntityUri) return label;
22
+
23
+ return (
24
+ <EntityUriLink className={styles.link} value={getEntityUriForLink(selectedEntity)} screen="graph">
25
+ {label}
26
+ </EntityUriLink>
27
+ );
28
+ };
29
+
30
+ return <ProfileBand entity={selectedEntity} renderLabel={renderLabel} />;
31
+ };
32
+
33
+ export default withContext(GraphStateContext, pick(['selectedEntity']), RightPanelProfileBand);
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import {mount, ReactWrapper} from 'enzyme';
3
+ import * as reactRedux from 'react-redux';
4
+ import {EntityUriLink, ProfileBand} from '@reltio/components';
5
+
6
+ import RightPanelProfileBand from '../RightPanelProfileBand';
7
+ import {GraphStateContext} from '../../../contexts/GraphStateContext';
8
+ import {GraphState} from '../../../types/graphDataTypes';
9
+
10
+ jest.mock('@reltio/components', () => ({
11
+ ...jest.requireActual<Record<string, unknown>>('@reltio/components'),
12
+ ProfileBand: () => null,
13
+ EntityUriLink: () => null
14
+ }));
15
+
16
+ const store = {
17
+ profile: {
18
+ entity: {
19
+ uri: 'uri1'
20
+ }
21
+ }
22
+ };
23
+
24
+ const setUp = ({selectedEntity = null} = {}) =>
25
+ mount(
26
+ <GraphStateContext.Provider value={{selectedEntity} as GraphState}>
27
+ <RightPanelProfileBand />
28
+ </GraphStateContext.Provider>
29
+ );
30
+
31
+ describe('RightPanelProfileBand tests', () => {
32
+ beforeAll(() => {
33
+ jest.spyOn(reactRedux, 'useSelector').mockImplementation((selector) => selector(store));
34
+ });
35
+
36
+ afterAll(() => {
37
+ jest.clearAllMocks();
38
+ });
39
+
40
+ it('should render ProfileBand with selectedEntity from context', () => {
41
+ const selectedEntity = {uri: 'uri2'};
42
+ const component = setUp({selectedEntity});
43
+ const profileBand = component.find(ProfileBand);
44
+ expect(profileBand).toHaveLength(1);
45
+ expect(profileBand.prop('entity')).toBe(selectedEntity);
46
+ });
47
+
48
+ it('should render standart label if selected entity equals current entity', () => {
49
+ const selectedEntity = {uri: store.profile.entity.uri};
50
+ const component = setUp({selectedEntity});
51
+ const label = component.find(ProfileBand).prop('renderLabel')('label');
52
+ expect(label).toBe('label');
53
+ });
54
+
55
+ it('should wrap label to EntityUriLink with correct props if selected entity does not equal current entity', () => {
56
+ const selectedEntity = {uri: 'uri2'};
57
+ const component = setUp({selectedEntity});
58
+ const label = new ReactWrapper(component.find(ProfileBand).prop('renderLabel')('label') as React.ReactElement);
59
+ expect(label.find(EntityUriLink)).toHaveLength(1);
60
+ expect(label.props()).toEqual({
61
+ className: 'link',
62
+ value: 'uri2',
63
+ screen: 'graph',
64
+ children: 'label'
65
+ });
66
+ });
67
+ });
@@ -0,0 +1,8 @@
1
+ import {makeStyles} from '@mui/styles';
2
+
3
+ export const useStyles = makeStyles((theme) => ({
4
+ link: {
5
+ textDecoration: 'none',
6
+ color: theme.palette.primary.main
7
+ }
8
+ }));
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import Typography from '@mui/material/Typography';
3
+
4
+ import i18n from 'ui-i18n';
5
+ import RelationshipTable from './components/RelationshipTable/RelationshipTable';
6
+ import RelationshipsFilters from './components/RelationshipsFilters/RelationshipsFilters';
7
+ import GraphAddRelationButton from './components/GraphAddRelationDialog/GraphAddRelationButton';
8
+ import {useStyles} from './styles';
9
+
10
+ const RightPanelRelationship = () => {
11
+ const styles = useStyles();
12
+
13
+ return (
14
+ <div className={styles.wrapper}>
15
+ <div className={styles.caption}>
16
+ <Typography variant="subtitle1">{i18n.text('Relationships')}</Typography>
17
+ <GraphAddRelationButton />
18
+ </div>
19
+ <RelationshipsFilters />
20
+ <RelationshipTable />
21
+ </div>
22
+ );
23
+ };
24
+
25
+ export default RightPanelRelationship;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import {shallow} from 'enzyme';
3
+
4
+ import RightPanelRelationship from '../RightPanelRelationship';
5
+ import RelationshipTable from '../components/RelationshipTable/RelationshipTable';
6
+ import RelationshipsFilters from '../components/RelationshipsFilters/RelationshipsFilters';
7
+ import GraphAddRelationButton from '../components/GraphAddRelationDialog/GraphAddRelationButton';
8
+
9
+ const setUp = () => shallow(<RightPanelRelationship />);
10
+
11
+ describe('RightPanelRelationship tests', () => {
12
+ it('should render main components', () => {
13
+ const component = setUp();
14
+ expect(component.find(GraphAddRelationButton)).toHaveLength(1);
15
+ expect(component.find(RelationshipsFilters)).toHaveLength(1);
16
+ expect(component.find(RelationshipTable)).toHaveLength(1);
17
+ });
18
+ });