@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,126 @@
1
+ import React, {useEffect, useMemo, useRef} from 'react';
2
+ import i18n from 'ui-i18n';
3
+ import {BasicTablePagination, LinearLoadIndicator, withContext} from '@reltio/components';
4
+ import classnames from 'classnames';
5
+
6
+ import {GraphStateContext} from '../../../../contexts/GraphStateContext';
7
+ import {RelationshipRow, RelationshipTableState} from '../../../../types/graphDataTypes';
8
+ import CollapsibleTable from '../CollapsibleTable/CollapsibleTable';
9
+ import HeadCellRenderer from './cell-renderers/HeadCellRenderer';
10
+ import DefaultCellRenderer from './cell-renderers/DefaultCellRenderer';
11
+ import ProfileCellRenderer from './cell-renderers/ProfileCellRenderer';
12
+ import ExpandedRowRenderer from './cell-renderers/ExpandedRowRenderer';
13
+ import ControlsCellRenderer from './cell-renderers/ControlsCellRenderer';
14
+ import {ROWS_PER_PAGE_OPTIONS} from '../../../../constants';
15
+ import {collapsibleTableRowClassName, useStyles} from './styles';
16
+
17
+ export const getRowKey = (index: number, data: RelationshipRow[]) => {
18
+ const row = data[index];
19
+ return row.relation.uri || `${index}`;
20
+ };
21
+
22
+ const RelationshipTable = ({
23
+ rowsData,
24
+ sorting,
25
+ onSort,
26
+ total,
27
+ page,
28
+ rowsPerPage,
29
+ onPageChange,
30
+ onRowsPerPageChange,
31
+ editingRelations,
32
+ loading
33
+ }: RelationshipTableState) => {
34
+ const styles = useStyles();
35
+
36
+ const columnsData = useMemo(
37
+ () => [
38
+ {
39
+ id: 'entityLabel',
40
+ label: i18n.text('Profile'),
41
+ headCellRenderer: HeadCellRenderer,
42
+ rowCellValueRenderer: ProfileCellRenderer,
43
+ sortable: true,
44
+ columnClassName: styles.profileColumn
45
+ },
46
+ {
47
+ id: 'relationTypeLabel',
48
+ label: i18n.text('Relationship type'),
49
+ headCellRenderer: HeadCellRenderer,
50
+ rowCellValueRenderer: DefaultCellRenderer,
51
+ sortable: true,
52
+ columnClassName: styles.relationshipTypeColumn
53
+ },
54
+ {
55
+ id: 'entityTypeLabel',
56
+ label: i18n.text('Entity Type'),
57
+ headCellRenderer: HeadCellRenderer,
58
+ rowCellValueRenderer: DefaultCellRenderer,
59
+ sortable: true,
60
+ columnClassName: styles.entityTypeColumn
61
+ },
62
+ {
63
+ id: 'controls',
64
+ label: '',
65
+ headCellRenderer: HeadCellRenderer,
66
+ rowCellValueRenderer: ControlsCellRenderer
67
+ }
68
+ ],
69
+ [styles]
70
+ );
71
+
72
+ const tableRef = useRef(null);
73
+
74
+ useEffect(() => {
75
+ tableRef.current?.resetScrollbarPosition();
76
+ }, [rowsData]);
77
+
78
+ const rowsDataWithExpandedInfo = useMemo(
79
+ () =>
80
+ rowsData.map((row) =>
81
+ editingRelations?.some((rel) => rel.initialRelation.uri === row?.relation?.uri)
82
+ ? {...row, expanded: true}
83
+ : row
84
+ ),
85
+ [rowsData, editingRelations]
86
+ );
87
+
88
+ const tableClasses = useMemo(
89
+ () => ({
90
+ tableRow: classnames(styles.row, collapsibleTableRowClassName)
91
+ }),
92
+ [styles]
93
+ );
94
+
95
+ return (
96
+ <div className={styles.tableWithPagination}>
97
+ <div className={styles.tableContainer}>
98
+ <CollapsibleTable
99
+ ref={tableRef}
100
+ columnsData={columnsData}
101
+ rowsData={rowsDataWithExpandedInfo}
102
+ sorting={sorting}
103
+ onSort={onSort}
104
+ getRowKey={getRowKey}
105
+ ExpandedRowRenderer={ExpandedRowRenderer}
106
+ defaultRowHeight={28}
107
+ classes={tableClasses}
108
+ />
109
+ </div>
110
+ {total > ROWS_PER_PAGE_OPTIONS[0] && (
111
+ <BasicTablePagination
112
+ count={total}
113
+ rowsPerPageOptions={ROWS_PER_PAGE_OPTIONS}
114
+ rowsPerPage={rowsPerPage}
115
+ onChangeRowsPerPage={onRowsPerPageChange}
116
+ page={page}
117
+ onChangePage={onPageChange}
118
+ basicTableRef={tableRef}
119
+ />
120
+ )}
121
+ {loading && <LinearLoadIndicator />}
122
+ </div>
123
+ );
124
+ };
125
+
126
+ export default withContext(GraphStateContext, ({relationshipTable}) => ({...relationshipTable}), RelationshipTable);
@@ -0,0 +1,176 @@
1
+ import React from 'react';
2
+ import {mount} from 'enzyme';
3
+ import {identity} from 'ramda';
4
+ import {BasicTablePagination, LinearLoadIndicator} from '@reltio/components';
5
+
6
+ import RelationshipTable from '../RelationshipTable';
7
+ import {GraphStateContext} from '../../../../../contexts/GraphStateContext';
8
+ import {GraphState} from '../../../../../types/graphDataTypes';
9
+ import CollapsibleTable from '../../CollapsibleTable/CollapsibleTable';
10
+ import HeadCellRenderer from '../cell-renderers/HeadCellRenderer';
11
+ import ProfileCellRenderer from '../cell-renderers/ProfileCellRenderer';
12
+ import DefaultCellRenderer from '../cell-renderers/DefaultCellRenderer';
13
+ import ControlsCellRenderer from '../cell-renderers/ControlsCellRenderer';
14
+ import ExpandedRowRenderer from '../cell-renderers/ExpandedRowRenderer';
15
+ import {ROWS_PER_PAGE_OPTIONS} from '../../../../../constants';
16
+
17
+ jest.mock('@reltio/components', () => ({
18
+ ...jest.requireActual<Record<string, unknown>>('@reltio/components'),
19
+ BasicTablePagination: () => null
20
+ }));
21
+
22
+ jest.mock('../../CollapsibleTable/CollapsibleTable', () => () => null);
23
+
24
+ const setUp = ({
25
+ rowsData = [],
26
+ editingRelations = [],
27
+ onSort = identity,
28
+ sorting = {order: 'asc'},
29
+ total = 0,
30
+ page = 0,
31
+ rowsPerPage = 25,
32
+ onPageChange = identity,
33
+ onRowsPerPageChange = identity,
34
+ loading = false
35
+ } = {}) => {
36
+ const relationshipTable = {
37
+ rowsData,
38
+ sorting,
39
+ onSort,
40
+ total,
41
+ page,
42
+ rowsPerPage,
43
+ onPageChange,
44
+ onRowsPerPageChange,
45
+ editingRelations,
46
+ loading
47
+ };
48
+ return mount(
49
+ <GraphStateContext.Provider value={{relationshipTable} as GraphState}>
50
+ <RelationshipTable />
51
+ </GraphStateContext.Provider>
52
+ );
53
+ };
54
+
55
+ describe('RelationshipTable tests', () => {
56
+ it('should render CollapsibleTable and BasicTablePagination', () => {
57
+ const component = setUp({total: 26});
58
+ expect(component.find(CollapsibleTable)).toHaveLength(1);
59
+ expect(component.find(BasicTablePagination)).toHaveLength(1);
60
+ });
61
+
62
+ it('should provide correct props for CollapsibleTable', () => {
63
+ const rowsData = [
64
+ {
65
+ entity: {uri: '1', type: '1'},
66
+ relation: {uri: 'r1', type: '1'},
67
+ entityLabel: 'entity label',
68
+ entityTypeLabel: 'entity type label',
69
+ relationTypeLabel: 'relation type label'
70
+ },
71
+ {
72
+ entity: {uri: '2', type: '2'},
73
+ relation: {uri: 'r2', type: '2'},
74
+ entityLabel: 'entity label2',
75
+ entityTypeLabel: 'entity type label2',
76
+ relationTypeLabel: 'relation type label2'
77
+ }
78
+ ];
79
+ const sorting = {
80
+ field: '1',
81
+ order: 'desc'
82
+ };
83
+ const editingRelations = [{initialRelation: {uri: 'r1'}, relation: {uri: 'r1'}}];
84
+ const onSort = jest.fn();
85
+ const component = setUp({rowsData, sorting, onSort, editingRelations});
86
+ const collapsibleTable = component.find(CollapsibleTable);
87
+ expect(collapsibleTable.prop('columnsData')).toEqual([
88
+ {
89
+ id: 'entityLabel',
90
+ label: 'Profile',
91
+ headCellRenderer: HeadCellRenderer,
92
+ rowCellValueRenderer: ProfileCellRenderer,
93
+ sortable: true,
94
+ columnClassName: 'profileColumn'
95
+ },
96
+ {
97
+ id: 'relationTypeLabel',
98
+ label: 'Relationship type',
99
+ headCellRenderer: HeadCellRenderer,
100
+ rowCellValueRenderer: DefaultCellRenderer,
101
+ sortable: true,
102
+ columnClassName: 'relationshipTypeColumn'
103
+ },
104
+ {
105
+ id: 'entityTypeLabel',
106
+ label: 'Entity Type',
107
+ headCellRenderer: HeadCellRenderer,
108
+ rowCellValueRenderer: DefaultCellRenderer,
109
+ sortable: true,
110
+ columnClassName: 'entityTypeColumn'
111
+ },
112
+ {
113
+ id: 'controls',
114
+ label: '',
115
+ headCellRenderer: HeadCellRenderer,
116
+ rowCellValueRenderer: ControlsCellRenderer
117
+ }
118
+ ]);
119
+ expect(collapsibleTable.prop('rowsData')).toEqual([
120
+ {
121
+ ...rowsData[0],
122
+ expanded: true
123
+ },
124
+ rowsData[1]
125
+ ]);
126
+ expect(collapsibleTable.prop('sorting')).toBe(sorting);
127
+ expect(collapsibleTable.prop('onSort')).toBe(onSort);
128
+ expect(collapsibleTable.prop('ExpandedRowRenderer')).toBe(ExpandedRowRenderer);
129
+ expect(collapsibleTable.prop('defaultRowHeight')).toBe(28);
130
+ expect(collapsibleTable.prop('getRowKey')(0, rowsData)).toBe('r1');
131
+ });
132
+
133
+ it('should provide correct props for BasicTablePagination', () => {
134
+ const total = 26;
135
+ const rowsPerPage = 25;
136
+ const page = 1;
137
+ const onPageChange = jest.fn();
138
+ const onRowsPerPageChange = jest.fn();
139
+ const component = setUp({
140
+ total,
141
+ rowsPerPage,
142
+ page,
143
+ onPageChange,
144
+ onRowsPerPageChange
145
+ });
146
+ const basicTablePagination = component.find(BasicTablePagination);
147
+ expect(basicTablePagination.prop('count')).toBe(total);
148
+ expect(basicTablePagination.prop('rowsPerPageOptions')).toBe(ROWS_PER_PAGE_OPTIONS);
149
+ expect(basicTablePagination.prop('rowsPerPage')).toBe(rowsPerPage);
150
+ expect(basicTablePagination.prop('onChangeRowsPerPage')).toBe(onRowsPerPageChange);
151
+ expect(basicTablePagination.prop('page')).toBe(page);
152
+ expect(basicTablePagination.prop('onChangePage')).toBe(onPageChange);
153
+ });
154
+
155
+ it('should not render BasicTablePagination if total is not more than ROWS_PER_PAGE_OPTIONS[0]', () => {
156
+ const component = setUp({total: 25});
157
+ expect(component.find(CollapsibleTable)).toHaveLength(1);
158
+ expect(component.find(BasicTablePagination)).toHaveLength(0);
159
+ });
160
+
161
+ it('should still render BasicTablePagination if total is not more than rowsPerPage but more than ROWS_PER_PAGE_OPTIONS[0]', () => {
162
+ const component = setUp({total: 26, rowsPerPage: 50});
163
+ expect(component.find(CollapsibleTable)).toHaveLength(1);
164
+ expect(component.find(BasicTablePagination)).toHaveLength(1);
165
+ });
166
+
167
+ it('should render LinearLoadIndicator if loading prop is passed', () => {
168
+ const component = setUp({loading: true});
169
+ expect(component.find(LinearLoadIndicator)).toHaveLength(1);
170
+ });
171
+
172
+ it('should not render LinearLoadIndicator if loading prop is not passed', () => {
173
+ const component = setUp();
174
+ expect(component.find(LinearLoadIndicator)).toHaveLength(0);
175
+ });
176
+ });
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import i18n from 'ui-i18n';
3
+ import classnames from 'classnames';
4
+ import {useSelector} from 'react-redux';
5
+ import {SmallIconButtonWithTooltip, withContext} from '@reltio/components';
6
+ import mdmModule from '@reltio/mdm-module';
7
+ import {checkMetadataForUpdate, checkMetadataForDelete, getRelationType, Mode} from '@reltio/mdm-sdk';
8
+ import EditIcon from '@mui/icons-material/Edit';
9
+
10
+ import {GraphStateContext} from '../../../../../contexts/GraphStateContext';
11
+ import {RelationshipRow} from '../../../../../types/graphDataTypes';
12
+ import DeleteRelationButton from './components/DeleteRelationButton';
13
+ import {useStyles} from './styles';
14
+
15
+ type Props = {
16
+ rowValue: RelationshipRow;
17
+ className?: string;
18
+ onEdit?: (uri: string) => void;
19
+ isEditing?: boolean;
20
+ };
21
+
22
+ const ControlsCellRenderer = ({
23
+ rowValue: {
24
+ relation: {uri, type}
25
+ },
26
+ className,
27
+ onEdit,
28
+ isEditing
29
+ }: Props) => {
30
+ const styles = useStyles();
31
+ const metadata = useSelector(mdmModule.selectors.getMetadata);
32
+ const relationType = getRelationType(metadata, type);
33
+ const canEdit = checkMetadataForUpdate(Mode.Editing, relationType);
34
+ const canDelete = checkMetadataForDelete(Mode.Editing, relationType);
35
+ return (
36
+ <div className={classnames(styles.controlsCell, className, {[styles.editingMode]: isEditing})}>
37
+ {canEdit && (
38
+ <SmallIconButtonWithTooltip
39
+ className={classnames(styles.editButton, {[styles.hidden]: isEditing})}
40
+ icon={EditIcon}
41
+ size={'XXS'}
42
+ tooltipTitle={i18n.text('Edit')}
43
+ data-reltio-id="reltio-edit-relationship-button"
44
+ onClick={() => onEdit(uri)}
45
+ />
46
+ )}
47
+ {canDelete && <DeleteRelationButton uri={uri} />}
48
+ </div>
49
+ );
50
+ };
51
+
52
+ export default withContext(
53
+ GraphStateContext,
54
+ ({relationshipTable: {onStartRelationEditing, editingRelations}}, props) => ({
55
+ onEdit: onStartRelationEditing,
56
+ isEditing: editingRelations.some((rel) => rel.initialRelation.uri === props?.rowValue.relation?.uri)
57
+ }),
58
+ ControlsCellRenderer
59
+ );
@@ -0,0 +1,29 @@
1
+ import React, {memo, ReactNode} from 'react';
2
+ import classnames from 'classnames';
3
+ import {ExpandedValueTooltip} from '@reltio/components';
4
+
5
+ import {useStyles} from './styles';
6
+
7
+ type Props = {
8
+ value?: ReactNode | string;
9
+ tooltip?: string;
10
+ className?: string;
11
+ onClick?: () => void;
12
+ };
13
+
14
+ const DefaultCellRenderer = ({value = '', tooltip, onClick, className}: Props) => {
15
+ const styles = useStyles();
16
+ tooltip = tooltip || (value as string);
17
+ return (
18
+ <ExpandedValueTooltip value={tooltip}>
19
+ <div
20
+ className={classnames(styles.defaultCell, className, {[styles.clickable]: !!onClick})}
21
+ onClick={onClick}
22
+ >
23
+ {value}
24
+ </div>
25
+ </ExpandedValueTooltip>
26
+ );
27
+ };
28
+
29
+ export default memo(DefaultCellRenderer);
@@ -0,0 +1,94 @@
1
+ import React, {useCallback, useMemo} from 'react';
2
+ import {useDispatch, useSelector} from 'react-redux';
3
+ import Button from '@mui/material/Button';
4
+ import {equals} from 'ramda';
5
+ import i18n from 'ui-i18n';
6
+
7
+ import {EditingConnection, Relation, validateConnectionRelation} from '@reltio/mdm-sdk';
8
+ import mdm, {profile} from '@reltio/mdm-module';
9
+ import {withContext, ConnectionEditor, useEditableConnection} from '@reltio/components';
10
+
11
+ import {RelationshipRow} from '../../../../../types/graphDataTypes';
12
+ import {GraphStateContext} from '../../../../../contexts/GraphStateContext';
13
+
14
+ import {useStyles} from './styles';
15
+
16
+ type Props = {
17
+ open: boolean;
18
+ rowValue: RelationshipRow;
19
+ editingRelationObject?: {initialRelation: Relation; relation: Relation};
20
+ onUpdateEditingRelation?: (relation: Relation) => void;
21
+ onCancelRelationEditing?: (uri: string) => void;
22
+ onSaveEditingRelation?: (oldRelation: Relation, newRelation: Relation) => void;
23
+ loading?: boolean;
24
+ };
25
+
26
+ export const ExpandedRowRenderer = ({
27
+ open,
28
+ editingRelationObject,
29
+ onUpdateEditingRelation,
30
+ onCancelRelationEditing,
31
+ onSaveEditingRelation
32
+ }: Props) => {
33
+ const dispatch = useDispatch();
34
+ const metadata = useSelector(mdm.selectors.getMetadata);
35
+ const {relation: editingRelation, initialRelation} = editingRelationObject;
36
+ const hasChanges = useMemo(() => !equals(initialRelation, editingRelation), [editingRelation, initialRelation]);
37
+ const styles = useStyles();
38
+ const onUpdateConnection = useCallback(
39
+ ({relation}: EditingConnection) => onUpdateEditingRelation(relation),
40
+ [onUpdateEditingRelation]
41
+ );
42
+
43
+ const handleCancelRelationEditing = useCallback(
44
+ () => onCancelRelationEditing(editingRelation.uri),
45
+ [onCancelRelationEditing, editingRelation.uri]
46
+ );
47
+ const connection = useMemo(() => ({relation: editingRelation}), [editingRelation]);
48
+ const {onAddAttributes, onChangeAttribute, onRemoveAttribute} = useEditableConnection({
49
+ connection,
50
+ onConnectionChange: onUpdateConnection
51
+ });
52
+
53
+ const validate = (relation: Relation) => {
54
+ const errors = validateConnectionRelation(metadata, {relation: {object: relation}});
55
+ dispatch(profile.errors.actions.errorsSet(errors));
56
+ return errors.length === 0;
57
+ };
58
+
59
+ const onSave = () => {
60
+ if (validate(editingRelation)) {
61
+ onSaveEditingRelation(initialRelation, editingRelation);
62
+ }
63
+ };
64
+
65
+ return open ? (
66
+ <div className={styles.expandedRow}>
67
+ <ConnectionEditor
68
+ connection={connection}
69
+ onAddAttributes={onAddAttributes}
70
+ onChangeAttribute={onChangeAttribute}
71
+ onRemoveAttribute={onRemoveAttribute}
72
+ />
73
+ <div className={styles.actionButtons}>
74
+ <Button onClick={handleCancelRelationEditing}>{i18n.text('Cancel')}</Button>
75
+ <Button color="primary" disabled={!hasChanges} onClick={onSave}>
76
+ {i18n.text('Save')}
77
+ </Button>
78
+ </div>
79
+ </div>
80
+ ) : null;
81
+ };
82
+
83
+ export default withContext(
84
+ GraphStateContext,
85
+ ({relationshipTable}, props) => ({
86
+ editingRelationObject: relationshipTable.editingRelations.find(
87
+ (rel) => rel.initialRelation.uri === props?.rowValue.relation?.uri
88
+ ),
89
+ onUpdateEditingRelation: relationshipTable.onUpdateEditingRelation,
90
+ onCancelRelationEditing: relationshipTable.onCancelRelationEditing,
91
+ onSaveEditingRelation: relationshipTable.onSaveEditingRelation
92
+ }),
93
+ ExpandedRowRenderer
94
+ );
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import classnames from 'classnames';
3
+ import DefaultHeadCellRenderer from 'react-components/dist/Table/DefaultHeadCellRenderer/DefaultHeadCellRenderer';
4
+ import {ExpandedValueTooltip} from '@reltio/components';
5
+
6
+ import {ColumnsDataItem} from '../../CollapsibleTable/types';
7
+ import {useStyles} from './styles';
8
+
9
+ type Props = {
10
+ className?: string;
11
+ headCellData: ColumnsDataItem;
12
+ };
13
+
14
+ const HeadCellRenderer = ({className, headCellData, ...otherProps}: Props) => {
15
+ const styles = useStyles();
16
+
17
+ return (
18
+ <div className={classnames(styles.headCell, className)}>
19
+ <DefaultHeadCellRenderer
20
+ {...otherProps}
21
+ headCellData={{
22
+ ...headCellData,
23
+ label: (
24
+ <ExpandedValueTooltip value={headCellData.label}>
25
+ <div className={styles.headLabel}>{headCellData.label}</div>
26
+ </ExpandedValueTooltip>
27
+ )
28
+ }}
29
+ />
30
+ </div>
31
+ );
32
+ };
33
+
34
+ export default HeadCellRenderer;
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import {EntityAvatar, withContext} from '@reltio/components';
3
+ import classnames from 'classnames';
4
+
5
+ import DefaultCellRenderer from './DefaultCellRenderer';
6
+ import {GraphStateContext} from '../../../../../contexts/GraphStateContext';
7
+ import {RelationshipRow} from '../../../../../types/graphDataTypes';
8
+ import {useStyles} from './styles';
9
+
10
+ type Props = {
11
+ value: string;
12
+ className?: string;
13
+ rowValue: RelationshipRow;
14
+ onClick?: (entityUri: string) => void;
15
+ };
16
+
17
+ export const ProfileCellRenderer = ({value, rowValue: {entity}, className, onClick}: Props) => {
18
+ const styles = useStyles();
19
+ const cellValue = (
20
+ <>
21
+ <EntityAvatar entity={entity} avatarClassName={styles.entityAvatar} />
22
+ {value}
23
+ </>
24
+ );
25
+ return (
26
+ <DefaultCellRenderer
27
+ value={cellValue}
28
+ tooltip={value}
29
+ className={classnames(styles.profileCell, className)}
30
+ onClick={() => onClick(entity.uri)}
31
+ />
32
+ );
33
+ };
34
+
35
+ export default withContext(
36
+ GraphStateContext,
37
+ ({onEntitySelect}) => ({
38
+ onClick: onEntitySelect
39
+ }),
40
+ ProfileCellRenderer
41
+ );
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+ import {mount} from 'enzyme';
3
+ import * as reactRedux from 'react-redux';
4
+ import {identity} from 'ramda';
5
+ import {SmallIconButtonWithTooltip} from '@reltio/components';
6
+
7
+ import ControlsCellRenderer from '../ControlsCellRenderer';
8
+ import {GraphStateContext} from '../../../../../../contexts/GraphStateContext';
9
+ import {GraphState, RelationshipRow} from '../../../../../../types/graphDataTypes';
10
+ import DeleteRelationButton from '../components/DeleteRelationButton';
11
+
12
+ const relation = {
13
+ uri: '1',
14
+ type: 'configuration/relationTypes/Family'
15
+ };
16
+
17
+ const setUp = ({rowValue = {relation}, onStartRelationEditing = identity} = {}) => {
18
+ const relationshipTable = {
19
+ onStartRelationEditing,
20
+ editingRelations: []
21
+ };
22
+ return mount(
23
+ <GraphStateContext.Provider value={{relationshipTable} as GraphState}>
24
+ <ControlsCellRenderer rowValue={rowValue as RelationshipRow} />
25
+ </GraphStateContext.Provider>
26
+ );
27
+ };
28
+
29
+ describe('ControlsCellRenderer tests', () => {
30
+ let store;
31
+ beforeEach(() => {
32
+ store = {
33
+ metadata: {
34
+ t1: {
35
+ relationTypes: [
36
+ {
37
+ access: ['READ', 'DELETE', 'UPDATE'],
38
+ uri: 'configuration/relationTypes/Family'
39
+ }
40
+ ]
41
+ }
42
+ },
43
+ tenant: {
44
+ id: 't1'
45
+ }
46
+ };
47
+ });
48
+ beforeAll(() => {
49
+ jest.spyOn(reactRedux, 'useSelector').mockImplementation((selector) => selector(store));
50
+ });
51
+
52
+ it('should not render edit button if there is no UPDATE permission', () => {
53
+ store.metadata.t1.relationTypes[0].access = ['READ', 'DELETE'];
54
+ const component = setUp();
55
+ expect(component.find(SmallIconButtonWithTooltip)).toHaveLength(1);
56
+ expect(component.find(SmallIconButtonWithTooltip)).not.toBe('Edit');
57
+ });
58
+
59
+ it('should not render delete button if there is no DELETE permission', () => {
60
+ store.metadata.t1.relationTypes[0].access = ['READ', 'UPDATE'];
61
+ const component = setUp();
62
+ expect(component.find(DeleteRelationButton)).toHaveLength(0);
63
+ });
64
+
65
+ it('should render edit button', () => {
66
+ const onEdit = jest.fn();
67
+ const component = setUp({onStartRelationEditing: onEdit});
68
+ expect(component.find(SmallIconButtonWithTooltip)).toHaveLength(2);
69
+ const editButton = component.find(SmallIconButtonWithTooltip).at(0);
70
+ expect(editButton.prop('tooltipTitle')).toBe('Edit');
71
+ (editButton.prop('onClick') as () => void)();
72
+ expect(onEdit).toHaveBeenCalledWith(relation.uri);
73
+ });
74
+
75
+ it('should render delete button', () => {
76
+ const component = setUp();
77
+ expect(component.find(DeleteRelationButton)).toHaveLength(1);
78
+ expect(component.find(DeleteRelationButton).prop('uri')).toBe(relation.uri);
79
+ });
80
+ });