@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,279 @@
1
+ import {useCallback, useEffect, useState, useContext} from 'react';
2
+ import {useDispatch, useSelector} from 'react-redux';
3
+ import Graph, {MultiGraph} from 'graphology';
4
+ import {difference, prop} from 'ramda';
5
+ import {
6
+ Entity,
7
+ getHops,
8
+ getRequestErrorMessage,
9
+ HopsResponse,
10
+ isDataTenantEntity,
11
+ isTempUri,
12
+ getLastUriPart,
13
+ createRelation,
14
+ getEntity,
15
+ removeRelation,
16
+ Relation,
17
+ Metadata,
18
+ GraphLayout,
19
+ isAbortError
20
+ } from '@reltio/mdm-sdk';
21
+ import i18n from 'ui-i18n';
22
+ import mdmModule, {ui} from '@reltio/mdm-module';
23
+ import {usePrevious, useSafePromise, PageRequestsAbortingContext} from '@reltio/components';
24
+
25
+ import {GraphPathType, GraphState} from '../types/graphDataTypes';
26
+ import {addRelationToHopsData, removeRelationFromHopsData, mergeHopsData} from '../utils/hopsData';
27
+ import {fillGraphWithHopsResponse, getIsolatedNodes, removeNodesFromGraph} from '../utils/graph';
28
+
29
+ export const useGraphLoader = (
30
+ entity: Entity,
31
+ graphTypeUri?: string,
32
+ layout?: GraphLayout
33
+ ): Pick<
34
+ GraphState,
35
+ | 'graphLoading'
36
+ | 'data'
37
+ | 'onAddRelation'
38
+ | 'onDeleteRelation'
39
+ | 'onCollapseEntity'
40
+ | 'onExpandEntity'
41
+ | 'graphologyGraph'
42
+ > => {
43
+ const [graphologyGraph, setGraphologyGraph] = useState<Graph>(null);
44
+ const dispatch = useDispatch();
45
+ const [data, setData] = useState<HopsResponse>(null);
46
+ const [loading, setLoading] = useState(false);
47
+ const entityUri = entity?.uri;
48
+ const isDTEntity = isDataTenantEntity(entity);
49
+ const metadata: Metadata = useSelector(mdmModule.selectors.getMetadata);
50
+ const safeLoadHopsPromise = useSafePromise();
51
+ const safeLoadHopsForEntityPromise = useSafePromise();
52
+ const isTreeLayout = layout === GraphLayout.TREE;
53
+ const prevLayout = usePrevious(layout);
54
+ const signal = useContext(PageRequestsAbortingContext);
55
+
56
+ const isPrevAndCurrentLayoutTree = prevLayout === GraphLayout.TREE && isTreeLayout;
57
+
58
+ const loadHopsForEntity = useCallback(
59
+ (uri: string, deep = 1) => {
60
+ return safeLoadHopsForEntityPromise(
61
+ getHops({
62
+ uri,
63
+ deep,
64
+ limitCreditsConsumption: true,
65
+ graphTypes: graphTypeUri ? [getLastUriPart(graphTypeUri)] : null,
66
+ activenessDate: null,
67
+ max: graphTypeUri ? 200 : 3000,
68
+ signal
69
+ })
70
+ );
71
+ },
72
+ [graphTypeUri, safeLoadHopsForEntityPromise, signal]
73
+ );
74
+
75
+ useEffect(() => {
76
+ if (entityUri && !isTempUri(entityUri) && !isDTEntity && !isTreeLayout) {
77
+ setLoading(true);
78
+ safeLoadHopsPromise(
79
+ getHops({
80
+ uri: entityUri,
81
+ deep: graphTypeUri ? 2 : 1,
82
+ limitCreditsConsumption: true,
83
+ graphTypes: graphTypeUri ? [getLastUriPart(graphTypeUri)] : null,
84
+ activenessDate: null,
85
+ max: graphTypeUri ? 200 : 3000,
86
+ signal
87
+ })
88
+ )
89
+ .then((data) => {
90
+ const graph = new MultiGraph();
91
+ fillGraphWithHopsResponse(graph, data);
92
+ setGraphologyGraph(graph);
93
+ setData(data);
94
+ })
95
+ .catch((error) => {
96
+ console.error(error);
97
+ setData(null);
98
+ if (!isAbortError(error)) {
99
+ dispatch(ui.actions.errorSet(getRequestErrorMessage(error, i18n.text('Something went wrong'))));
100
+ }
101
+ })
102
+ .finally(() => {
103
+ setLoading(false);
104
+ });
105
+ }
106
+
107
+ return () => {
108
+ setGraphologyGraph(null);
109
+ setData(null);
110
+ setLoading(false);
111
+ };
112
+ }, [entityUri, isDTEntity, dispatch, graphTypeUri, isPrevAndCurrentLayoutTree]);
113
+
114
+ const onAddRelation = useCallback(
115
+ async ({startEntityUri, endEntityUri, relationType, attributes, startDate, endDate}) => {
116
+ try {
117
+ setLoading(true);
118
+ const response = await createRelation({
119
+ startEntityUri,
120
+ endEntityUri,
121
+ relationType,
122
+ attributes,
123
+ startDate,
124
+ endDate
125
+ });
126
+
127
+ if (!response?.[0]?.successful) {
128
+ throw response?.[0];
129
+ }
130
+
131
+ const respondedRelation: Relation = response[0].object;
132
+ const relatedEntityUri =
133
+ startEntityUri === entityUri
134
+ ? respondedRelation.endObject.objectURI
135
+ : respondedRelation.startObject.objectURI;
136
+
137
+ const relatedEntity = await getEntity(relatedEntityUri, {select: 'label'} as any);
138
+
139
+ if (startEntityUri === entityUri) {
140
+ respondedRelation.endObject.label = relatedEntity.label;
141
+ } else {
142
+ respondedRelation.startObject.label = relatedEntity.label;
143
+ }
144
+
145
+ const newData = addRelationToHopsData(data, respondedRelation, metadata);
146
+ fillGraphWithHopsResponse(graphologyGraph, newData);
147
+
148
+ const extremities = [respondedRelation.startObject.objectURI, respondedRelation.endObject.objectURI];
149
+ const entitiesUris = data.entities.map(prop('uri'));
150
+
151
+ extremities.forEach((node) => {
152
+ if (entitiesUris.includes(node)) {
153
+ const traversedRelationsCount = graphologyGraph.getNodeAttribute(
154
+ node,
155
+ 'traversedRelationsCount'
156
+ );
157
+ graphologyGraph.setNodeAttribute(node, 'traversedRelationsCount', traversedRelationsCount + 1);
158
+ }
159
+ });
160
+
161
+ setData(newData);
162
+ } catch (error) {
163
+ dispatch(ui.actions.errorSet(getRequestErrorMessage(error, i18n.text('Something went wrong'))));
164
+ throw error;
165
+ } finally {
166
+ setLoading(false);
167
+ }
168
+ },
169
+ [dispatch, data, graphologyGraph, metadata]
170
+ );
171
+
172
+ const onDeleteRelation = useCallback(
173
+ (uri: string) => {
174
+ setLoading(true);
175
+ removeRelation(uri)
176
+ .then(() => {
177
+ const extremities = graphologyGraph.extremities(uri);
178
+ extremities.forEach((node) => {
179
+ const traversedRelationsCount = graphologyGraph.getNodeAttribute(
180
+ node,
181
+ 'traversedRelationsCount'
182
+ );
183
+ graphologyGraph.setNodeAttribute(node, 'traversedRelationsCount', traversedRelationsCount - 1);
184
+ });
185
+ graphologyGraph.dropEdge(uri);
186
+ const {updatedData, removedEntitiesUris} = removeRelationFromHopsData(
187
+ entityUri,
188
+ uri,
189
+ graphologyGraph,
190
+ data
191
+ );
192
+ removeNodesFromGraph(graphologyGraph, removedEntitiesUris);
193
+ setData(updatedData);
194
+ })
195
+ .catch((error) => {
196
+ dispatch(ui.actions.errorSet(getRequestErrorMessage(error, i18n.text('Something went wrong'))));
197
+ })
198
+ .finally(() => {
199
+ setLoading(false);
200
+ });
201
+ },
202
+ [dispatch, graphologyGraph, entityUri, data]
203
+ );
204
+
205
+ const onCollapseEntity = useCallback(
206
+ (uri: string, path: GraphPathType) => {
207
+ const {nodes = []} = path;
208
+
209
+ const neighbors = difference(graphologyGraph.neighbors(uri), nodes);
210
+ const nodesToHide = getIsolatedNodes(entityUri, uri, neighbors, graphologyGraph);
211
+ nodesToHide.forEach((node) => {
212
+ if (node !== entityUri && node !== uri) {
213
+ graphologyGraph.setNodeAttribute(node, 'hidden', true);
214
+ }
215
+ });
216
+ },
217
+ [entityUri, graphologyGraph]
218
+ );
219
+
220
+ const onExpandEntity = useCallback(
221
+ (uri: string) => {
222
+ if (uri && !isTempUri(uri) && !isDTEntity) {
223
+ const untraversedRelationsCount = graphologyGraph.getNodeAttribute(uri, 'untraversedRelationsCount');
224
+
225
+ const neighbors = graphologyGraph.neighbors(uri);
226
+ neighbors.forEach((node) => {
227
+ graphologyGraph.setNodeAttribute(node, 'hidden', false);
228
+ });
229
+
230
+ if (untraversedRelationsCount > 0) {
231
+ setLoading(true);
232
+ loadHopsForEntity(uri)
233
+ .then((newData) => {
234
+ const mergedData = mergeHopsData(data, newData, uri);
235
+
236
+ fillGraphWithHopsResponse(graphologyGraph, newData);
237
+ const loadedEntity = newData.entities.find((entity) => entity.uri === uri);
238
+ graphologyGraph.setNodeAttribute(
239
+ uri,
240
+ 'untraversedRelationsCount',
241
+ loadedEntity.untraversedRelations
242
+ );
243
+ graphologyGraph.setNodeAttribute(
244
+ uri,
245
+ 'traversedRelationsCount',
246
+ loadedEntity.traversedRelations
247
+ );
248
+
249
+ setData(mergedData);
250
+ })
251
+ .catch((error) => {
252
+ console.error(error);
253
+ if (!isAbortError(error)) {
254
+ dispatch(
255
+ ui.actions.errorSet(
256
+ getRequestErrorMessage(error, i18n.text('Something went wrong'))
257
+ )
258
+ );
259
+ }
260
+ })
261
+ .finally(() => {
262
+ setLoading(false);
263
+ });
264
+ }
265
+ }
266
+ },
267
+ [data, dispatch, graphologyGraph, isDTEntity, loadHopsForEntity]
268
+ );
269
+
270
+ return {
271
+ graphLoading: loading,
272
+ data,
273
+ graphologyGraph,
274
+ onAddRelation,
275
+ onDeleteRelation,
276
+ onCollapseEntity,
277
+ onExpandEntity
278
+ };
279
+ };
@@ -0,0 +1,36 @@
1
+ import React, {useMemo} from 'react';
2
+ import i18n from 'ui-i18n';
3
+ import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
4
+ import RightPanelRelationship from '../components/RightPanelRelationship/RightPanelRelationship';
5
+ import RightPanelEntityDetails from '../components/RightPanelEntityDetails/RightPanelEntityDetails';
6
+ import {ActivePanel} from '../components/GraphRightSidePanel/GraphRightSidePanel';
7
+ import RelationshipIcon from '../components/GraphRightSidePanel/icons/relationship-icon.svg';
8
+ import {RightPanelTab} from '@reltio/components';
9
+
10
+ export const useGraphRightSidePanelElements = (): {tabs: RightPanelTab[]} => {
11
+ const tabs = useMemo(
12
+ () => [
13
+ {
14
+ buttonProps: {
15
+ id: ActivePanel.Relationship,
16
+ icon: RelationshipIcon,
17
+ tooltipTitle: i18n.text('Relationship'),
18
+ showForDisabled: true
19
+ },
20
+ content: <RightPanelRelationship />
21
+ },
22
+ {
23
+ buttonProps: {
24
+ id: ActivePanel.EntityDetails,
25
+ icon: InfoOutlinedIcon,
26
+ tooltipTitle: i18n.text('Entity Details'),
27
+ showForDisabled: true
28
+ },
29
+ content: <RightPanelEntityDetails />
30
+ }
31
+ ],
32
+ []
33
+ );
34
+
35
+ return {tabs};
36
+ };
@@ -0,0 +1,40 @@
1
+ import {Entity, GraphLayout} from '@reltio/mdm-sdk';
2
+ import {GraphState} from '../types/graphDataTypes';
3
+ import {useGraphLoader} from './useGraphLoader';
4
+ import {useSelectedEntity} from './useSelectedEntity';
5
+ import {useRelationshipTable} from './useRelationshipTable';
6
+ import {useGraphType} from './useGraphType';
7
+ import {useGraphLayoutSelector} from './useGraphLayoutSelector';
8
+
9
+ export const useGraphState = (entity: Entity, initialGraphTypeUri?: string, graphLayout?: GraphLayout): GraphState => {
10
+ const {layout, setLayout} = useGraphLayoutSelector(graphLayout);
11
+ const {graphTypeUri, setGraphTypeUri} = useGraphType(entity, initialGraphTypeUri, setLayout);
12
+
13
+ const {graphLoading, data, graphologyGraph, onAddRelation, onDeleteRelation, onCollapseEntity, onExpandEntity} =
14
+ useGraphLoader(entity, graphTypeUri, layout);
15
+ const {selectedEntity, onEntitySelect, selectedEntityLoading} = useSelectedEntity(entity, data);
16
+ const relationshipTable = useRelationshipTable({
17
+ data,
18
+ selectedEntityUri: selectedEntity?.uri,
19
+ mainEntityUri: entity?.uri,
20
+ graphTypeUri
21
+ });
22
+
23
+ return {
24
+ graphLoading,
25
+ data,
26
+ graphologyGraph,
27
+ selectedEntity,
28
+ selectedEntityLoading,
29
+ graphTypeUri,
30
+ relationshipTable,
31
+ layout,
32
+ onAddRelation,
33
+ onDeleteRelation,
34
+ onCollapseEntity,
35
+ onExpandEntity,
36
+ onEntitySelect,
37
+ setGraphTypeUri,
38
+ setLayout
39
+ };
40
+ };
@@ -0,0 +1,32 @@
1
+ import {Entity, getGraphTypesForEntityType, GraphLayout} from '@reltio/mdm-sdk';
2
+ import {useEffect, useState} from 'react';
3
+
4
+ import mdm from '@reltio/mdm-module';
5
+ import {useSelector} from 'react-redux';
6
+ import {GraphState} from '../types/graphDataTypes';
7
+
8
+ export const useGraphType = (
9
+ entity: Entity,
10
+ initialGraphTypeUri?: string,
11
+ setLayout?: (GraphLayout) => void
12
+ ): Pick<GraphState, 'graphTypeUri' | 'setGraphTypeUri'> => {
13
+ const [graphTypeUri, setGraphTypeUri] = useState<string>(null);
14
+
15
+ const onSetGraphTypeUri = (graphTypeUri) => {
16
+ setGraphTypeUri(graphTypeUri);
17
+ if (!graphTypeUri) {
18
+ setLayout(GraphLayout.SIMPLE_NETWORK);
19
+ }
20
+ };
21
+ const metadata = useSelector(mdm.selectors.getMetadata);
22
+ useEffect(() => {
23
+ const isCorrectGraphType = getGraphTypesForEntityType(metadata, entity.type).some(
24
+ ({uri}) => initialGraphTypeUri === uri
25
+ );
26
+ if (isCorrectGraphType) {
27
+ setGraphTypeUri(initialGraphTypeUri);
28
+ }
29
+ }, [initialGraphTypeUri, entity, metadata]);
30
+
31
+ return {graphTypeUri, setGraphTypeUri: onSetGraphTypeUri};
32
+ };
@@ -0,0 +1,212 @@
1
+ import {useCallback, useEffect, useMemo, useState} from 'react';
2
+ import {either, equals, filter, identity, map, pipe, prop, sort, uniqBy, zipObj, ifElse, includes, T} from 'ramda';
3
+ import {useDispatch, useSelector} from 'react-redux';
4
+ import {
5
+ EntitiesMap,
6
+ getEndObjectUri,
7
+ getEntityTypeLabel,
8
+ getLabel,
9
+ getRelationTypeLabelFromMetadata,
10
+ getStartObjectUri,
11
+ HopEntity,
12
+ HopRelation,
13
+ HopsResponse,
14
+ Metadata,
15
+ utils,
16
+ getRelation,
17
+ Relation,
18
+ updateRelation,
19
+ getRequestErrorMessage
20
+ } from '@reltio/mdm-sdk';
21
+
22
+ import mdm, {ui} from '@reltio/mdm-module';
23
+ import {useRelationshipTableFilters} from './useRelationshipTableFilters';
24
+ import {RelationshipRow, RelationshipTableState} from '../types/graphDataTypes';
25
+ import {ROWS_PER_PAGE_OPTIONS} from '../constants';
26
+
27
+ import i18n from 'ui-i18n';
28
+
29
+ const getSecondEntityUri = (firstEntityUri: string, relation: HopRelation) => {
30
+ const startEntityUri = getStartObjectUri(relation);
31
+ const endEntityUri = getEndObjectUri(relation);
32
+ return startEntityUri === firstEntityUri ? endEntityUri : startEntityUri;
33
+ };
34
+
35
+ const getRelationTypeLabel = (metadata: Metadata, relation: HopRelation, entityUri: string) => {
36
+ const {startObject, endObject, type} = relation;
37
+ const {directionalLabel} = getStartObjectUri(relation) === entityUri ? startObject : endObject;
38
+ return directionalLabel || getRelationTypeLabelFromMetadata(metadata, type);
39
+ };
40
+
41
+ type Props = {
42
+ data: HopsResponse;
43
+ selectedEntityUri: string;
44
+ mainEntityUri: string;
45
+ graphTypeUri: string;
46
+ };
47
+
48
+ export const useRelationshipTable = ({
49
+ data,
50
+ selectedEntityUri,
51
+ mainEntityUri,
52
+ graphTypeUri
53
+ }: Props): RelationshipTableState => {
54
+ const [sorting, setSorting] = useState({
55
+ field: '',
56
+ order: 'asc'
57
+ });
58
+ const [page, setPage] = useState(0);
59
+ const [rowsPerPage, setRowsPerPage] = useState(ROWS_PER_PAGE_OPTIONS[0]);
60
+ const [editingRelations, setEditingRelations] = useState<Array<{initialRelation: Relation; relation: Relation}>>(
61
+ []
62
+ );
63
+ const [loading, setLoading] = useState(false);
64
+ const dispatch = useDispatch();
65
+ const metadata = useSelector(mdm.selectors.getMetadata);
66
+
67
+ const entitiesMap: EntitiesMap<HopEntity> = useMemo(() => {
68
+ const entities = data?.entities || [];
69
+ return zipObj(entities.map(prop('uri')), entities);
70
+ }, [data?.entities]);
71
+
72
+ const allRowsData: RelationshipRow[] = useMemo(
73
+ () =>
74
+ pipe(
75
+ filter(
76
+ either(
77
+ pipe(getStartObjectUri, equals(selectedEntityUri)),
78
+ pipe(getEndObjectUri, equals(selectedEntityUri))
79
+ )
80
+ ),
81
+ uniqBy(prop('uri')),
82
+ map((relation: HopRelation) => {
83
+ const entity = entitiesMap[getSecondEntityUri(selectedEntityUri, relation)];
84
+ return {
85
+ relation,
86
+ entity,
87
+ entityLabel: getLabel(entity.label),
88
+ entityTypeLabel: getEntityTypeLabel(metadata, entity),
89
+ relationTypeLabel: getRelationTypeLabel(metadata, relation, entity.uri)
90
+ };
91
+ })
92
+ )(data?.relations || []),
93
+ [data, selectedEntityUri, entitiesMap, metadata]
94
+ );
95
+
96
+ const {
97
+ searchText,
98
+ onChangeSearchText,
99
+ filters,
100
+ onFilter,
101
+ relationTypesOptions,
102
+ entityTypesOptions
103
+ } = useRelationshipTableFilters(allRowsData);
104
+
105
+ const filteredRowsData: RelationshipRow[] = useMemo(
106
+ () =>
107
+ pipe(
108
+ filter(({entityLabel, entity, relation}: RelationshipRow) => {
109
+ const {entityTypesUris, relationTypesUris} = filters;
110
+ return (
111
+ utils.strings.search(entityLabel, searchText) &&
112
+ ifElse(prop('length'), includes(relation.type), T)(relationTypesUris) &&
113
+ ifElse(prop('length'), includes(entity.type), T)(entityTypesUris)
114
+ );
115
+ }),
116
+ sorting.field
117
+ ? sort((a: RelationshipRow, b: RelationshipRow) =>
118
+ utils.strings.sort(sorting.order, a[sorting.field], b[sorting.field])
119
+ )
120
+ : identity
121
+ )(allRowsData),
122
+ [allRowsData, sorting, searchText, filters]
123
+ );
124
+
125
+ const pagedRowsData: RelationshipRow[] = useMemo(
126
+ () => filteredRowsData.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage),
127
+ [filteredRowsData, page, rowsPerPage]
128
+ );
129
+
130
+ const onStartRelationEditing = useCallback(
131
+ (uri: string) => {
132
+ setLoading(true);
133
+ getRelation(uri)
134
+ .then((relation) => {
135
+ setEditingRelations((prev) => [...prev, {initialRelation: relation, relation}]);
136
+ })
137
+ .catch((error) => {
138
+ dispatch(
139
+ ui.actions.errorSet(
140
+ getRequestErrorMessage(error, i18n.text("Can't load relationship's attributes"))
141
+ )
142
+ );
143
+ })
144
+ .finally(() => setLoading(false));
145
+ },
146
+ [dispatch]
147
+ );
148
+
149
+ const onUpdateEditingRelation = useCallback((relation: Relation) => {
150
+ setEditingRelations((prev) =>
151
+ prev.map((rel) => (rel.relation.uri === relation.uri ? {...rel, relation} : rel))
152
+ );
153
+ }, []);
154
+
155
+ useEffect(() => {
156
+ setPage(0);
157
+ onChangeSearchText('');
158
+ }, [selectedEntityUri, graphTypeUri, onChangeSearchText, onFilter]);
159
+
160
+ useEffect(() => {
161
+ onFilter({entityTypesUris: [], relationTypesUris: []});
162
+ }, [graphTypeUri, mainEntityUri, onFilter]);
163
+
164
+ useEffect(() => {
165
+ setPage(0);
166
+ }, [sorting, searchText, filters]);
167
+
168
+ const onCancelRelationEditing = useCallback((uri: string) => {
169
+ setEditingRelations((prev) => prev.filter((rel) => rel.relation.uri !== uri));
170
+ }, []);
171
+
172
+ const onSaveEditingRelation = useCallback(
173
+ (oldRelation: Relation, newRelation: Relation) => {
174
+ setLoading(true);
175
+ updateRelation({
176
+ oldRelation,
177
+ newRelation
178
+ })
179
+ .then(() => {
180
+ onCancelRelationEditing(newRelation.uri);
181
+ })
182
+ .catch((error) => {
183
+ dispatch(ui.actions.errorSet(getRequestErrorMessage(error, i18n.text("Can't edit relationship"))));
184
+ })
185
+ .finally(() => setLoading(false));
186
+ },
187
+ [onCancelRelationEditing, dispatch]
188
+ );
189
+
190
+ return {
191
+ rowsData: pagedRowsData,
192
+ onSort: setSorting,
193
+ sorting: sorting,
194
+ searchText,
195
+ onChangeSearchText,
196
+ filters,
197
+ onFilter,
198
+ entityTypesOptions,
199
+ relationTypesOptions,
200
+ editingRelations,
201
+ onStartRelationEditing,
202
+ onCancelRelationEditing,
203
+ onUpdateEditingRelation,
204
+ total: filteredRowsData.length,
205
+ page: page,
206
+ rowsPerPage: rowsPerPage,
207
+ onPageChange: setPage,
208
+ onRowsPerPageChange: setRowsPerPage,
209
+ onSaveEditingRelation,
210
+ loading
211
+ };
212
+ };
@@ -0,0 +1,43 @@
1
+ import {useState, useMemo} from 'react';
2
+ import {useSelector} from 'react-redux';
3
+ import mdmModule from '@reltio/mdm-module';
4
+ import {pipe, map, uniq, concat, __} from 'ramda';
5
+ import {getRelationType, getEntityType, Metadata, TEntityType, TRelationType} from '@reltio/mdm-sdk';
6
+ import {Filters, RelationshipRow} from '../types/graphDataTypes';
7
+
8
+ export const useRelationshipTableFilters = (allRowsData: RelationshipRow[]) => {
9
+ const [searchText, setSearchText] = useState('');
10
+ const [filters, setFilters] = useState<Filters>({entityTypesUris: [], relationTypesUris: []});
11
+
12
+ const metadata: Metadata = useSelector(mdmModule.selectors.getMetadata);
13
+
14
+ const entityTypesOptions: TEntityType[] = useMemo(
15
+ () =>
16
+ pipe(
17
+ map(({entity}) => entity.type),
18
+ concat(__, filters.entityTypesUris),
19
+ uniq,
20
+ map(getEntityType(metadata))
21
+ )(allRowsData),
22
+ [allRowsData, metadata, filters.entityTypesUris]
23
+ );
24
+ const relationTypesOptions: TRelationType[] = useMemo(
25
+ () =>
26
+ pipe(
27
+ map(({relation}) => relation.type),
28
+ concat(__, filters.relationTypesUris),
29
+ uniq,
30
+ map(getRelationType(metadata))
31
+ )(allRowsData),
32
+ [allRowsData, metadata, filters.relationTypesUris]
33
+ );
34
+
35
+ return {
36
+ searchText,
37
+ onChangeSearchText: setSearchText,
38
+ filters,
39
+ onFilter: setFilters,
40
+ entityTypesOptions,
41
+ relationTypesOptions
42
+ };
43
+ };