datajunction-ui 0.0.1-rc.9 → 0.0.2-0.dev1

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 (244) hide show
  1. package/.env +2 -0
  2. package/.prettierignore +3 -1
  3. package/Makefile +9 -0
  4. package/cleanup-deps.sh +70 -0
  5. package/dj-logo.svg +10 -0
  6. package/package.json +53 -14
  7. package/public/favicon.ico +0 -0
  8. package/public/index.html +1 -1
  9. package/runit.sh +30 -0
  10. package/runit2.sh +30 -0
  11. package/src/__tests__/reportWebVitals.test.jsx +44 -0
  12. package/src/app/__tests__/__snapshots__/index.test.tsx.snap +5 -109
  13. package/src/app/components/AddNodeDropdown.jsx +44 -0
  14. package/src/app/components/ListGroupItem.jsx +9 -1
  15. package/src/app/components/NamespaceHeader.jsx +4 -13
  16. package/src/app/components/NodeListActions.jsx +69 -0
  17. package/src/app/components/NodeMaterializationDelete.jsx +90 -0
  18. package/src/app/components/NotificationBell.tsx +223 -0
  19. package/src/app/components/QueryInfo.jsx +172 -0
  20. package/src/app/components/Search.jsx +94 -0
  21. package/src/app/components/Tab.jsx +8 -1
  22. package/src/app/components/ToggleSwitch.jsx +20 -0
  23. package/src/app/components/UserMenu.tsx +100 -0
  24. package/src/app/components/__tests__/NodeListActions.test.jsx +94 -0
  25. package/src/app/components/__tests__/NodeMaterializationDelete.test.jsx +263 -0
  26. package/src/app/components/__tests__/NotificationBell.test.tsx +302 -0
  27. package/src/app/components/__tests__/QueryInfo.test.jsx +183 -0
  28. package/src/app/components/__tests__/Search.test.jsx +307 -0
  29. package/src/app/components/__tests__/Tab.test.jsx +27 -0
  30. package/src/app/components/__tests__/ToggleSwitch.test.jsx +43 -0
  31. package/src/app/components/__tests__/UserMenu.test.tsx +241 -0
  32. package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +8 -3
  33. package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +2 -18
  34. package/src/app/components/djgraph/Collapse.jsx +47 -0
  35. package/src/app/components/djgraph/DJNode.jsx +61 -83
  36. package/src/app/components/djgraph/DJNodeColumns.jsx +75 -0
  37. package/src/app/components/djgraph/DJNodeDimensions.jsx +75 -0
  38. package/src/app/components/djgraph/LayoutFlow.jsx +106 -0
  39. package/src/app/components/djgraph/__tests__/Collapse.test.jsx +51 -0
  40. package/src/app/components/djgraph/__tests__/DJNodeColumns.test.jsx +83 -0
  41. package/src/app/components/djgraph/__tests__/DJNodeDimensions.test.jsx +118 -0
  42. package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +84 -40
  43. package/src/app/components/forms/Action.jsx +8 -0
  44. package/src/app/components/forms/NodeNameField.jsx +64 -0
  45. package/src/app/components/search.css +17 -0
  46. package/src/app/constants.js +2 -0
  47. package/src/app/icons/AddItemIcon.jsx +16 -0
  48. package/src/app/icons/AlertIcon.jsx +33 -0
  49. package/src/app/icons/CollapsedIcon.jsx +15 -0
  50. package/src/app/icons/CommitIcon.jsx +45 -0
  51. package/src/app/icons/DJLogo.jsx +36 -0
  52. package/src/app/icons/DeleteIcon.jsx +21 -0
  53. package/src/app/icons/DiffIcon.jsx +63 -0
  54. package/src/app/icons/EditIcon.jsx +18 -0
  55. package/src/app/icons/ExpandedIcon.jsx +15 -0
  56. package/src/app/icons/EyeIcon.jsx +20 -0
  57. package/src/app/icons/FilterIcon.jsx +7 -0
  58. package/src/app/icons/HorizontalHierarchyIcon.jsx +15 -0
  59. package/src/app/icons/InvalidIcon.jsx +16 -0
  60. package/src/app/icons/JupyterExportIcon.jsx +25 -0
  61. package/src/app/icons/LoadingIcon.jsx +14 -0
  62. package/src/app/icons/NodeIcon.jsx +49 -0
  63. package/src/app/icons/NotificationIcon.jsx +27 -0
  64. package/src/app/icons/PythonIcon.jsx +14 -0
  65. package/src/app/icons/SettingsIcon.jsx +28 -0
  66. package/src/app/icons/TableIcon.jsx +14 -0
  67. package/src/app/icons/ValidIcon.jsx +16 -0
  68. package/src/app/icons/WrenchIcon.jsx +36 -0
  69. package/src/app/index.tsx +130 -37
  70. package/src/app/pages/AddEditNodePage/AlertMessage.jsx +10 -0
  71. package/src/app/pages/AddEditNodePage/ColumnMetadata.jsx +61 -0
  72. package/src/app/pages/AddEditNodePage/ColumnsMetadataInput.jsx +72 -0
  73. package/src/app/pages/AddEditNodePage/ColumnsSelect.jsx +84 -0
  74. package/src/app/pages/AddEditNodePage/CustomMetadataField.jsx +144 -0
  75. package/src/app/pages/AddEditNodePage/DescriptionField.jsx +17 -0
  76. package/src/app/pages/AddEditNodePage/DisplayNameField.jsx +16 -0
  77. package/src/app/pages/AddEditNodePage/ExperimentationExtension.jsx +338 -0
  78. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +64 -0
  79. package/src/app/pages/AddEditNodePage/FullNameField.jsx +38 -0
  80. package/src/app/pages/AddEditNodePage/Loadable.jsx +20 -0
  81. package/src/app/pages/AddEditNodePage/MetricMetadataFields.jsx +75 -0
  82. package/src/app/pages/AddEditNodePage/MetricQueryField.jsx +71 -0
  83. package/src/app/pages/AddEditNodePage/NamespaceField.jsx +40 -0
  84. package/src/app/pages/AddEditNodePage/NodeModeField.jsx +14 -0
  85. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +94 -0
  86. package/src/app/pages/AddEditNodePage/OwnersField.jsx +54 -0
  87. package/src/app/pages/AddEditNodePage/RequiredDimensionsSelect.jsx +54 -0
  88. package/src/app/pages/AddEditNodePage/TagsField.jsx +47 -0
  89. package/src/app/pages/AddEditNodePage/UpstreamNodeField.jsx +49 -0
  90. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +110 -0
  91. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +291 -0
  92. package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +75 -0
  93. package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +31 -0
  94. package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
  95. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +54 -0
  96. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +3 -0
  97. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +3 -0
  98. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +224 -0
  99. package/src/app/pages/AddEditNodePage/index.jsx +545 -0
  100. package/src/app/pages/AddEditTagPage/Loadable.jsx +16 -0
  101. package/src/app/pages/AddEditTagPage/__tests__/AddEditTagPage.test.jsx +107 -0
  102. package/src/app/pages/AddEditTagPage/index.jsx +132 -0
  103. package/src/app/pages/CubeBuilderPage/DimensionsSelect.jsx +152 -0
  104. package/src/app/pages/CubeBuilderPage/Loadable.jsx +16 -0
  105. package/src/app/pages/CubeBuilderPage/MetricsSelect.jsx +75 -0
  106. package/src/app/pages/CubeBuilderPage/__tests__/index.test.jsx +373 -0
  107. package/src/app/pages/CubeBuilderPage/index.jsx +291 -0
  108. package/src/app/pages/LoginPage/LoginForm.jsx +124 -0
  109. package/src/app/pages/LoginPage/SignupForm.jsx +156 -0
  110. package/src/app/pages/LoginPage/__tests__/index.test.jsx +97 -0
  111. package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
  112. package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
  113. package/src/app/pages/LoginPage/index.jsx +17 -0
  114. package/src/app/pages/NamespacePage/AddNamespacePopover.jsx +85 -0
  115. package/src/app/pages/NamespacePage/Explorer.jsx +232 -0
  116. package/src/app/pages/NamespacePage/FieldControl.jsx +21 -0
  117. package/src/app/pages/NamespacePage/NodeModeSelect.jsx +27 -0
  118. package/src/app/pages/NamespacePage/NodeTypeSelect.jsx +30 -0
  119. package/src/app/pages/NamespacePage/TagSelect.jsx +44 -0
  120. package/src/app/pages/NamespacePage/UserSelect.jsx +47 -0
  121. package/src/app/pages/NamespacePage/__tests__/AddNamespacePopover.test.jsx +283 -0
  122. package/src/app/pages/NamespacePage/__tests__/index.test.jsx +331 -0
  123. package/src/app/pages/NamespacePage/index.jsx +356 -42
  124. package/src/app/pages/NodePage/AddBackfillPopover.jsx +165 -0
  125. package/src/app/pages/NodePage/AddComplexDimensionLinkPopover.jsx +367 -0
  126. package/src/app/pages/NodePage/AddMaterializationPopover.jsx +222 -0
  127. package/src/app/pages/NodePage/AvailabilityStateBlock.jsx +67 -0
  128. package/src/app/pages/NodePage/ClientCodePopover.jsx +94 -0
  129. package/src/app/pages/NodePage/DimensionFilter.jsx +86 -0
  130. package/src/app/pages/NodePage/EditColumnDescriptionPopover.jsx +116 -0
  131. package/src/app/pages/NodePage/EditColumnPopover.jsx +116 -0
  132. package/src/app/pages/NodePage/LinkDimensionPopover.jsx +164 -0
  133. package/src/app/pages/NodePage/ManageDimensionLinksDialog.jsx +526 -0
  134. package/src/app/pages/NodePage/MaterializationConfigField.jsx +60 -0
  135. package/src/app/pages/NodePage/NodeColumnTab.jsx +421 -30
  136. package/src/app/pages/NodePage/NodeDependenciesTab.jsx +153 -0
  137. package/src/app/pages/NodePage/NodeGraphTab.jsx +119 -148
  138. package/src/app/pages/NodePage/NodeHistory.jsx +236 -0
  139. package/src/app/pages/NodePage/NodeInfoTab.jsx +346 -49
  140. package/src/app/pages/NodePage/NodeLineageTab.jsx +84 -0
  141. package/src/app/pages/NodePage/NodeMaterializationTab.jsx +585 -0
  142. package/src/app/pages/NodePage/NodeRevisionMaterializationTab.jsx +58 -0
  143. package/src/app/pages/NodePage/NodeStatus.jsx +100 -31
  144. package/src/app/pages/NodePage/NodeValidateTab.jsx +367 -0
  145. package/src/app/pages/NodePage/NodesWithDimension.jsx +42 -0
  146. package/src/app/pages/NodePage/NotebookDownload.jsx +36 -0
  147. package/src/app/pages/NodePage/PartitionColumnPopover.jsx +151 -0
  148. package/src/app/pages/NodePage/PartitionValueForm.jsx +60 -0
  149. package/src/app/pages/NodePage/RevisionDiff.jsx +209 -0
  150. package/src/app/pages/NodePage/WatchNodeButton.jsx +226 -0
  151. package/src/app/pages/NodePage/__tests__/AddBackfillPopover.test.jsx +56 -0
  152. package/src/app/pages/NodePage/__tests__/AddComplexDimensionLinkPopover.test.jsx +459 -0
  153. package/src/app/pages/NodePage/__tests__/AddMaterializationPopover.test.jsx +87 -0
  154. package/src/app/pages/NodePage/__tests__/DimensionFilter.test.jsx +74 -0
  155. package/src/app/pages/NodePage/__tests__/EditColumnDescriptionPopover.test.jsx +149 -0
  156. package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +144 -0
  157. package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +132 -0
  158. package/src/app/pages/NodePage/__tests__/ManageDimensionLinksDialog.test.jsx +390 -0
  159. package/src/app/pages/NodePage/__tests__/NodeColumnTab.test.jsx +166 -0
  160. package/src/app/pages/NodePage/__tests__/NodeDependenciesTab.test.jsx +151 -0
  161. package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +595 -0
  162. package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +58 -0
  163. package/src/app/pages/NodePage/__tests__/NodeMaterializationTab.test.jsx +190 -0
  164. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +882 -0
  165. package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
  166. package/src/app/pages/NodePage/__tests__/RevisionDiff.test.jsx +164 -0
  167. package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +19 -0
  168. package/src/app/pages/NodePage/index.jsx +190 -44
  169. package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
  170. package/src/app/pages/NotificationsPage/Loadable.jsx +6 -0
  171. package/src/app/pages/NotificationsPage/__tests__/index.test.jsx +287 -0
  172. package/src/app/pages/NotificationsPage/index.jsx +136 -0
  173. package/src/app/pages/OverviewPage/ByStatusPanel.jsx +69 -0
  174. package/src/app/pages/OverviewPage/DimensionNodeUsagePanel.jsx +48 -0
  175. package/src/app/pages/OverviewPage/GovernanceWarningsPanel.jsx +107 -0
  176. package/src/app/pages/OverviewPage/Loadable.jsx +16 -0
  177. package/src/app/pages/OverviewPage/NodesByTypePanel.jsx +63 -0
  178. package/src/app/pages/OverviewPage/OverviewPanel.jsx +94 -0
  179. package/src/app/pages/OverviewPage/TrendsPanel.jsx +66 -0
  180. package/src/app/pages/OverviewPage/__tests__/ByStatusPanel.test.jsx +36 -0
  181. package/src/app/pages/OverviewPage/__tests__/DimensionNodeUsagePanel.test.jsx +76 -0
  182. package/src/app/pages/OverviewPage/__tests__/GovernanceWarningsPanel.test.jsx +77 -0
  183. package/src/app/pages/OverviewPage/__tests__/NodesByTypePanel.test.jsx +86 -0
  184. package/src/app/pages/OverviewPage/__tests__/OverviewPanel.test.jsx +78 -0
  185. package/src/app/pages/OverviewPage/__tests__/TrendsPanel.test.jsx +120 -0
  186. package/src/app/pages/OverviewPage/__tests__/index.test.jsx +54 -0
  187. package/src/app/pages/OverviewPage/index.jsx +22 -0
  188. package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
  189. package/src/app/pages/RegisterTablePage/__tests__/RegisterTablePage.test.jsx +112 -0
  190. package/src/app/pages/RegisterTablePage/__tests__/__snapshots__/RegisterTablePage.test.jsx.snap +38 -0
  191. package/src/app/pages/RegisterTablePage/index.jsx +142 -0
  192. package/src/app/pages/Root/__tests__/index.test.jsx +44 -0
  193. package/src/app/pages/Root/index.tsx +92 -10
  194. package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
  195. package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
  196. package/src/app/pages/SQLBuilderPage/index.jsx +390 -0
  197. package/src/app/pages/SettingsPage/CreateServiceAccountModal.jsx +152 -0
  198. package/src/app/pages/SettingsPage/Loadable.jsx +16 -0
  199. package/src/app/pages/SettingsPage/NotificationSubscriptionsSection.jsx +189 -0
  200. package/src/app/pages/SettingsPage/ProfileSection.jsx +41 -0
  201. package/src/app/pages/SettingsPage/ServiceAccountsSection.jsx +95 -0
  202. package/src/app/pages/SettingsPage/__tests__/CreateServiceAccountModal.test.jsx +318 -0
  203. package/src/app/pages/SettingsPage/__tests__/NotificationSubscriptionsSection.test.jsx +233 -0
  204. package/src/app/pages/SettingsPage/__tests__/ProfileSection.test.jsx +65 -0
  205. package/src/app/pages/SettingsPage/__tests__/ServiceAccountsSection.test.jsx +150 -0
  206. package/src/app/pages/SettingsPage/__tests__/index.test.jsx +184 -0
  207. package/src/app/pages/SettingsPage/index.jsx +148 -0
  208. package/src/app/pages/TagPage/Loadable.jsx +16 -0
  209. package/src/app/pages/TagPage/__tests__/TagPage.test.jsx +70 -0
  210. package/src/app/pages/TagPage/index.jsx +79 -0
  211. package/src/app/services/DJService.js +1444 -21
  212. package/src/app/services/__tests__/DJService.test.jsx +2118 -0
  213. package/src/app/utils/__tests__/date.test.js +198 -0
  214. package/src/app/utils/date.js +65 -0
  215. package/src/index.tsx +1 -0
  216. package/src/mocks/mockNodes.jsx +1477 -0
  217. package/src/setupTests.ts +31 -1
  218. package/src/styles/dag.css +117 -5
  219. package/src/styles/index.css +1028 -31
  220. package/src/styles/loading.css +34 -0
  221. package/src/styles/login.css +81 -0
  222. package/src/styles/nav-bar.css +274 -0
  223. package/src/styles/node-creation.scss +276 -0
  224. package/src/styles/node-list.css +4 -0
  225. package/src/styles/overview.css +72 -0
  226. package/src/styles/settings.css +787 -0
  227. package/src/styles/sorted-table.css +15 -0
  228. package/src/styles/styles.scss +44 -0
  229. package/src/styles/styles.scss.d.ts +9 -0
  230. package/src/utils/form.jsx +23 -0
  231. package/webpack.config.js +17 -6
  232. package/.babelrc +0 -4
  233. package/.env.local +0 -4
  234. package/.env.production +0 -1
  235. package/.github/pull_request_template.md +0 -11
  236. package/.github/workflows/ci.yml +0 -33
  237. package/.vscode/extensions.json +0 -7
  238. package/.vscode/launch.json +0 -15
  239. package/.vscode/settings.json +0 -25
  240. package/Dockerfile +0 -7
  241. package/src/app/pages/ListNamespacesPage/Loadable.jsx +0 -14
  242. package/src/app/pages/ListNamespacesPage/index.jsx +0 -62
  243. package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +0 -45
  244. package/src/app/pages/NamespacePage/__tests__/index.test.tsx +0 -14
@@ -1,168 +1,139 @@
1
- import React, { useCallback, useContext, useEffect, useMemo } from 'react';
2
- import ReactFlow, {
3
- addEdge,
4
- MiniMap,
5
- Controls,
6
- Background,
7
- useNodesState,
8
- useEdgesState,
9
- MarkerType,
10
- } from 'reactflow';
1
+ import { useContext } from 'react';
2
+ import { MarkerType } from 'reactflow';
11
3
 
12
4
  import '../../../styles/dag.css';
13
5
  import 'reactflow/dist/style.css';
14
- import DJNode from '../../components/djgraph/DJNode';
15
- import dagre from 'dagre';
16
6
  import DJClientContext from '../../providers/djclient';
7
+ import LayoutFlow from '../../components/djgraph/LayoutFlow';
17
8
 
18
- const NodeLineage = djNode => {
9
+ const NodeGraphTab = djNode => {
19
10
  const djClient = useContext(DJClientContext).DataJunctionAPI;
20
- const nodeTypes = useMemo(() => ({ DJNode: DJNode }), []);
21
11
 
22
- const [nodes, setNodes, onNodesChange] = useNodesState([]);
23
- const [edges, setEdges, onEdgesChange] = useEdgesState([]);
24
-
25
- const minimapStyle = {
26
- height: 100,
27
- width: 150,
28
- };
29
-
30
- const dagreGraph = useMemo(() => new dagre.graphlib.Graph(), []);
31
- dagreGraph.setDefaultEdgeLabel(() => ({}));
32
-
33
- useEffect(() => {
34
- const setElementsLayout = (
35
- nodes,
36
- edges,
37
- direction = 'LR',
38
- nodeWidth = 800,
39
- nodeHeight = 150,
40
- ) => {
41
- const isHorizontal = direction === 'TB';
42
- dagreGraph.setGraph({ rankdir: direction });
43
-
44
- nodes.forEach(node => {
45
- dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
46
- });
47
-
48
- edges.forEach(edge => {
49
- dagreGraph.setEdge(edge.source, edge.target);
50
- });
51
-
52
- dagre.layout(dagreGraph);
53
-
54
- nodes.forEach(node => {
55
- const nodeWithPosition = dagreGraph.node(node.id);
56
- node.targetPosition = isHorizontal ? 'left' : 'top';
57
- node.sourcePosition = isHorizontal ? 'right' : 'bottom';
58
- node.position = {
59
- x: nodeWithPosition.x - nodeWidth / 2,
60
- y: nodeWithPosition.y - nodeHeight / 2,
12
+ const createNode = node => {
13
+ const primary_key = node.columns
14
+ .filter(col =>
15
+ col.attributes.some(attr => attr.attribute_type.name === 'primary_key'),
16
+ )
17
+ .map(col => col.name);
18
+ const dimensionLinkForeignKeys = node.dimension_links
19
+ ? node.dimension_links.flatMap(link =>
20
+ Object.keys(link.foreign_keys).map(key => key.split('.').slice(-1)),
21
+ )
22
+ : [];
23
+ const column_names = node.columns
24
+ .map(col => {
25
+ return {
26
+ name: col.name,
27
+ type: col.type,
28
+ dimension: col.dimension !== null ? col.dimension.name : null,
29
+ order: primary_key.includes(col.name)
30
+ ? -1
31
+ : dimensionLinkForeignKeys.includes(col.name)
32
+ ? 0
33
+ : 1,
61
34
  };
62
- return node;
63
- });
64
-
65
- return { nodes, edges };
35
+ })
36
+ .sort((a, b) => a.order - b.order);
37
+ return {
38
+ id: String(node.name),
39
+ type: 'DJNode',
40
+ data: {
41
+ label:
42
+ node.table !== null
43
+ ? String(node.schema_ + '.' + node.table)
44
+ : 'default.' + node.name,
45
+ table: node.table,
46
+ name: String(node.name),
47
+ display_name: String(node.display_name),
48
+ type: node.type,
49
+ primary_key: primary_key,
50
+ column_names: column_names,
51
+ is_current: node.name === djNode.djNode.name,
52
+ },
66
53
  };
54
+ };
67
55
 
68
- const dagFetch = async () => {
69
- let upstreams = await djClient.upstreams(djNode.djNode.name);
70
- let downstreams = await djClient.downstreams(djNode.djNode.name);
71
- var djNodes = [djNode.djNode];
72
- for (const iterable of [upstreams, downstreams]) {
73
- for (const item of iterable) {
74
- djNodes.push(item);
75
- }
76
- }
77
- let edges = [];
78
- djNodes.forEach(obj => {
79
- obj.parents.forEach(parent => {
80
- if (parent.name) {
81
- edges.push({
82
- id: obj.name + '-' + parent.name,
83
- target: obj.name,
84
- source: parent.name,
85
- animated: true,
86
- markerEnd: {
56
+ const dimensionEdges = node => {
57
+ return node.dimension_links === undefined
58
+ ? []
59
+ : node.dimension_links.flatMap(link => {
60
+ return Object.keys(link.foreign_keys).map(fk => {
61
+ return {
62
+ id:
63
+ link.dimension.name +
64
+ '->' +
65
+ node.name +
66
+ '=' +
67
+ link.foreign_keys[fk] +
68
+ '->' +
69
+ fk,
70
+ source: link.dimension.name,
71
+ sourceHandle: link.foreign_keys[fk],
72
+ target: node.name,
73
+ targetHandle: fk,
74
+ draggable: true,
75
+ markerStart: {
87
76
  type: MarkerType.Arrow,
77
+ width: 20,
78
+ height: 20,
79
+ color: '#b0b9c2',
80
+ },
81
+ style: {
82
+ strokeWidth: 3,
83
+ stroke: '#b0b9c2',
88
84
  },
89
- });
90
- }
85
+ };
86
+ });
91
87
  });
88
+ };
92
89
 
93
- obj.columns.forEach(col => {
94
- if (col.dimension) {
95
- edges.push({
96
- id: obj.name + '-' + col.dimension.name,
97
- target: obj.name,
98
- source: col.dimension.name,
99
- draggable: true,
100
- });
101
- }
102
- });
103
- });
104
- const nodes = djNodes.map(node => {
105
- const primary_key = node.columns
106
- .filter(col =>
107
- col.attributes.some(
108
- attr => attr.attribute_type.name === 'primary_key',
109
- ),
110
- )
111
- .map(col => col.name);
112
- const column_names = node.columns.map(col => {
113
- return { name: col.name, type: col.type };
114
- });
90
+ const parentEdges = node => {
91
+ return node.parents
92
+ .filter(parent => parent.name)
93
+ .map(parent => {
115
94
  return {
116
- id: String(node.name),
117
- type: 'DJNode',
118
- data: {
119
- label:
120
- node.table !== null
121
- ? String(node.schema_ + '.' + node.table)
122
- : 'default.' + node.name,
123
- table: node.table,
124
- name: String(node.name),
125
- display_name: String(node.display_name),
126
- type: node.type,
127
- primary_key: primary_key,
128
- column_names: column_names,
129
- // dimensions: dimensions,
95
+ id: node.name + '-' + parent.name,
96
+ source: parent.name,
97
+ sourceHandle: parent.name,
98
+ target: node.name,
99
+ targetHandle: node.name,
100
+ animated: true,
101
+ markerEnd: {
102
+ type: MarkerType.Arrow,
103
+ },
104
+ style: {
105
+ strokeWidth: 3,
106
+ stroke: '#b0b9c2',
130
107
  },
131
- // parentNode: [node.name.split(".").slice(-2, -1)],
132
- // extent: 'parent',
133
108
  };
134
109
  });
135
- console.log(djNodes);
136
- setNodes(nodes);
137
- setEdges(edges);
138
- setElementsLayout(nodes, edges);
139
- };
140
-
141
- dagFetch();
142
- }, [dagreGraph, djNode.djNode, setEdges, setNodes]);
143
-
144
- const onConnect = useCallback(
145
- params => setEdges(eds => addEdge(params, eds)),
146
- [setEdges],
147
- );
110
+ };
148
111
 
149
- return (
150
- <div style={{ height: '600px' }}>
151
- <ReactFlow
152
- nodes={nodes}
153
- edges={edges}
154
- nodeTypes={nodeTypes}
155
- onNodesChange={onNodesChange}
156
- onEdgesChange={onEdgesChange}
157
- onConnect={onConnect}
158
- snapToGrid={true}
159
- fitView
160
- >
161
- <MiniMap style={minimapStyle} zoomable pannable />
162
- <Controls />
163
- <Background color="#aaa" gap={16} />
164
- </ReactFlow>
165
- </div>
166
- );
112
+ const dagFetch = async (getLayoutedElements, setNodes, setEdges) => {
113
+ let related_nodes = djNode.djNode
114
+ ? await djClient.node_dag(djNode.djNode.name)
115
+ : [];
116
+ var djNodes = djNode.djNode ? [djNode.djNode] : [];
117
+ for (const iterable of [related_nodes]) {
118
+ for (const item of iterable) {
119
+ if (item.type !== 'cube') {
120
+ djNodes.push(item);
121
+ }
122
+ }
123
+ }
124
+ let edges = [];
125
+ djNodes.forEach(node => {
126
+ edges = edges.concat(parentEdges(node));
127
+ edges = edges.concat(dimensionEdges(node));
128
+ });
129
+ const nodes = djNodes.map(node => createNode(node));
130
+
131
+ // use dagre to determine the position of the parents (the DJ nodes)
132
+ // the positions of the columns are relative to each DJ node
133
+ getLayoutedElements(nodes, edges);
134
+ setNodes(nodes);
135
+ setEdges(edges);
136
+ };
137
+ return LayoutFlow(djNode, dagFetch);
167
138
  };
168
- export default NodeLineage;
139
+ export default NodeGraphTab;
@@ -0,0 +1,236 @@
1
+ import { useEffect, useState } from 'react';
2
+ import * as React from 'react';
3
+ import DiffIcon from '../../icons/DiffIcon';
4
+ import { labelize } from '../../../utils/form';
5
+ import CommitIcon from '../../icons/CommitIcon';
6
+
7
+ export default function NodeHistory({ node, djClient }) {
8
+ const [history, setHistory] = useState([]);
9
+
10
+ useEffect(() => {
11
+ const fetchData = async () => {
12
+ if (node) {
13
+ const data = await djClient.history('node', node.name);
14
+ setHistory(data);
15
+ }
16
+ };
17
+ fetchData().catch(console.error);
18
+ }, [djClient, node]);
19
+
20
+ const eventData = event => {
21
+ const standard = (
22
+ <>
23
+ <a href={'#'} className={'highlight-svg'} title="Browse Details">
24
+ <CommitIcon /> Details
25
+ </a>
26
+ </>
27
+ );
28
+
29
+ if (event.activity_type === 'update' && event.entity_type === 'node') {
30
+ return (
31
+ <>
32
+ <a href={`/nodes/${event.node}/revisions/${event.details.version}`}>
33
+ <span className={`badge version`}>{event.details.version}</span>
34
+ </a>
35
+ <a
36
+ href={`/nodes/${event.node}/revisions/${event.details.version}`}
37
+ className={'highlight-svg'}
38
+ title="View Diff"
39
+ >
40
+ <DiffIcon /> Diff
41
+ </a>
42
+ </>
43
+ );
44
+ }
45
+ return '';
46
+ };
47
+
48
+ const eventDescription = event => {
49
+ if (event.activity_type === 'create' && event.entity_type === 'node') {
50
+ return (
51
+ <div className="history-left">
52
+ <b style={{ textTransform: 'capitalize' }}>{event.activity_type}</b>{' '}
53
+ {event.entity_type}{' '}
54
+ <b>
55
+ <a href={'/nodes/' + event.entity_name}>{event.entity_name}</a>
56
+ </b>
57
+ </div>
58
+ );
59
+ }
60
+ if (
61
+ ['create', 'update', 'delete'].includes(event.activity_type) &&
62
+ event.entity_type === 'link'
63
+ ) {
64
+ return (
65
+ <div className="history-left">
66
+ <b style={{ textTransform: 'capitalize' }}>{event.activity_type}</b>{' '}
67
+ {event.entity_type} from{' '}
68
+ <b>
69
+ <a href={'/nodes/' + event.entity_name}>{event.entity_name}</a>
70
+ </b>{' '}
71
+ to{' '}
72
+ <b>
73
+ <a href={'/nodes/' + event.details.dimension}>
74
+ {event.details.dimension}
75
+ </a>
76
+ </b>
77
+ </div>
78
+ );
79
+ }
80
+ if (event.activity_type === 'refresh') {
81
+ return (
82
+ <div className="history-left">
83
+ <b style={{ textTransform: 'capitalize' }}>{event.activity_type}</b>{' '}
84
+ {event.entity_type}{' '}
85
+ <b>
86
+ <a href={'/nodes/' + event.entity_name}>{event.entity_name}</a>
87
+ </b>
88
+ </div>
89
+ );
90
+ }
91
+ if (event.activity_type === 'update' && event.entity_type === 'node') {
92
+ if (event.details?.old_owners) {
93
+ return (
94
+ <div className="history-left">
95
+ <b style={{ textTransform: 'capitalize' }}>Ownership Change</b> for{' '}
96
+ {event.entity_type}{' '}
97
+ <b>
98
+ <a href={'/nodes/' + event.entity_name}>{event.entity_name}</a>
99
+ </b>
100
+ <small>
101
+ {' '}
102
+ to{' '}
103
+ {event.details?.new_owners.map(owner => (
104
+ <span className="badge version" style={{ margin: '2px' }}>
105
+ {owner}
106
+ </span>
107
+ ))}
108
+ </small>
109
+ </div>
110
+ );
111
+ }
112
+ return (
113
+ <div className="history-left">
114
+ <b style={{ textTransform: 'capitalize' }}>{event.activity_type}</b>{' '}
115
+ {event.entity_type}{' '}
116
+ <b>
117
+ <a href={'/nodes/' + event.entity_name}>{event.entity_name}</a>
118
+ </b>
119
+ </div>
120
+ );
121
+ }
122
+ if (event.activity_type === 'tag' && event.entity_type === 'node') {
123
+ return (
124
+ <div className="history-left">
125
+ Add tag{event.details.tags.length > 1 ? 's' : ''}{' '}
126
+ {event.details.tags.map(tag => (
127
+ <span className={'badge version'}>
128
+ <a href={`/tags/${tag}`}>{tag}</a>
129
+ </span>
130
+ ))}
131
+ </div>
132
+ );
133
+ }
134
+ if (event.activity_type === 'create' && event.entity_type === 'partition') {
135
+ return (
136
+ <div className="history-left">
137
+ Set <b>{event.details.partition.type_} partition</b> on{' '}
138
+ <a href={'/nodes/' + event.node}>{event.details.column}</a>
139
+ </div>
140
+ );
141
+ }
142
+
143
+ if (
144
+ event.activity_type === 'set_attribute' &&
145
+ event.entity_type === 'column_attribute'
146
+ ) {
147
+ return (
148
+ <div className="history-left">
149
+ <b>Set column attributes</b> on{' '}
150
+ <b>
151
+ <a href={'/nodes/' + event.node}>{event.node}</a>
152
+ </b>
153
+ </div>
154
+ );
155
+ }
156
+
157
+ if (event.entity_type === 'materialization') {
158
+ return (
159
+ <div className="history-left">
160
+ <span style={{ textTransform: 'capitalize' }}>
161
+ {event.activity_type}
162
+ </span>{' '}
163
+ <b>{event.entity_type}</b>{' '}
164
+ <a href={`/nodes/${event.node}/materializations`}>
165
+ {event.entity_name}
166
+ </a>
167
+ </div>
168
+ );
169
+ }
170
+
171
+ if (
172
+ event.activity_type === 'status_change' &&
173
+ event.entity_type === 'node'
174
+ ) {
175
+ return (
176
+ <div className="history-left">
177
+ <b style={{ textTransform: 'capitalize' }}>
178
+ {labelize(event.activity_type)}
179
+ </b>{' '}
180
+ on <a href={`/nodes/${event.node}`}>{event.node}</a> from{' '}
181
+ <b>{event.pre.status}</b> to <b>{event.post.status}</b>
182
+ </div>
183
+ );
184
+ }
185
+
186
+ if (
187
+ event.activity_type === 'create' &&
188
+ event.entity_type === 'availability'
189
+ ) {
190
+ return (
191
+ <div className="history-left">
192
+ <b>Materialized</b> table{' '}
193
+ <code>
194
+ {event.post.catalog}.{event.post.schema_}.{event.post.table}
195
+ </code>{' '}
196
+ with partitions between {event.post.min_temporal_partition} and{' '}
197
+ {event.post.max_temporal_partition} available for{' '}
198
+ <a href={'/nodes/' + event.node}>{event.node}</a>.
199
+ </div>
200
+ );
201
+ }
202
+
203
+ if (event.activity_type === 'create' && event.entity_type === 'backfill') {
204
+ return (
205
+ <div className="history-left">
206
+ <b>Backfill</b> created for materialization{' '}
207
+ {event.details.materialization} for partition{' '}
208
+ {event.details.partition[0].column_name} from{' '}
209
+ {event.details.partition[0].range[0]} to{' '}
210
+ {event.details.partition[0].range[1]}
211
+ </div>
212
+ );
213
+ }
214
+ };
215
+
216
+ const removeTagNodeEventsWithoutTags = event =>
217
+ event.activity_type !== 'tag' ||
218
+ (event.activity_type === 'tag' &&
219
+ event.entity_type === 'node' &&
220
+ event.details.tags.length > 0);
221
+
222
+ return (
223
+ <ul className="history-border" role="list" aria-label="Activity">
224
+ {history.filter(removeTagNodeEventsWithoutTags).map(event => (
225
+ <li key={`history-row-${event.id}`} className="history">
226
+ {eventDescription(event)}
227
+ <div className={'history-small'}>
228
+ done by <a href="#">{event.user ? event.user : 'unknown'}</a> on{' '}
229
+ {new Date(Date.parse(event.created_at)).toLocaleString()}
230
+ </div>
231
+ <div className="history-right">{eventData(event)}</div>
232
+ </li>
233
+ ))}
234
+ </ul>
235
+ );
236
+ }