datajunction-ui 0.0.1-rc.2 → 0.0.1-rc.20

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 (135) hide show
  1. package/.env +1 -0
  2. package/.prettierignore +3 -1
  3. package/dj-logo.svg +10 -0
  4. package/package.json +43 -13
  5. package/public/favicon.ico +0 -0
  6. package/src/__tests__/reportWebVitals.test.jsx +44 -0
  7. package/src/app/__tests__/__snapshots__/index.test.tsx.snap +5 -39
  8. package/src/app/components/DeleteNode.jsx +79 -0
  9. package/src/app/components/ListGroupItem.jsx +8 -1
  10. package/src/app/components/NamespaceHeader.jsx +4 -13
  11. package/src/app/components/QueryInfo.jsx +77 -0
  12. package/src/app/components/Tab.jsx +3 -2
  13. package/src/app/components/ToggleSwitch.jsx +20 -0
  14. package/src/app/components/__tests__/QueryInfo.test.jsx +55 -0
  15. package/src/app/components/__tests__/Tab.test.jsx +27 -0
  16. package/src/app/components/__tests__/ToggleSwitch.test.jsx +43 -0
  17. package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +3 -0
  18. package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +2 -18
  19. package/src/app/components/djgraph/Collapse.jsx +46 -0
  20. package/src/app/components/djgraph/DJNode.jsx +60 -82
  21. package/src/app/components/djgraph/DJNodeColumns.jsx +71 -0
  22. package/src/app/components/djgraph/DJNodeDimensions.jsx +75 -0
  23. package/src/app/components/djgraph/LayoutFlow.jsx +104 -0
  24. package/src/app/components/djgraph/__tests__/Collapse.test.jsx +51 -0
  25. package/src/app/components/djgraph/__tests__/DJNodeColumns.test.jsx +83 -0
  26. package/src/app/components/djgraph/__tests__/DJNodeDimensions.test.jsx +118 -0
  27. package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +84 -40
  28. package/src/app/constants.js +2 -0
  29. package/src/app/icons/AlertIcon.jsx +32 -0
  30. package/src/app/icons/CollapsedIcon.jsx +15 -0
  31. package/src/app/icons/DJLogo.jsx +36 -0
  32. package/src/app/icons/DeleteIcon.jsx +21 -0
  33. package/src/app/icons/EditIcon.jsx +18 -0
  34. package/src/app/icons/ExpandedIcon.jsx +15 -0
  35. package/src/app/icons/HorizontalHierarchyIcon.jsx +15 -0
  36. package/src/app/icons/InvalidIcon.jsx +14 -0
  37. package/src/app/icons/PythonIcon.jsx +52 -0
  38. package/src/app/icons/TableIcon.jsx +14 -0
  39. package/src/app/icons/ValidIcon.jsx +14 -0
  40. package/src/app/index.tsx +79 -26
  41. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +46 -0
  42. package/src/app/pages/AddEditNodePage/FullNameField.jsx +37 -0
  43. package/src/app/pages/AddEditNodePage/Loadable.jsx +16 -0
  44. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +89 -0
  45. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +77 -0
  46. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +93 -0
  47. package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +75 -0
  48. package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +31 -0
  49. package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
  50. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +53 -0
  51. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +53 -0
  52. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +3 -0
  53. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +178 -0
  54. package/src/app/pages/AddEditNodePage/index.jsx +357 -0
  55. package/src/app/pages/LoginPage/__tests__/index.test.jsx +70 -0
  56. package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
  57. package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
  58. package/src/app/pages/LoginPage/index.jsx +90 -0
  59. package/src/app/pages/NamespacePage/Explorer.jsx +57 -0
  60. package/src/app/pages/NamespacePage/Loadable.jsx +9 -7
  61. package/src/app/pages/NamespacePage/__tests__/index.test.jsx +95 -0
  62. package/src/app/pages/NamespacePage/index.jsx +131 -31
  63. package/src/app/pages/NodePage/ClientCodePopover.jsx +32 -0
  64. package/src/app/pages/NodePage/EditColumnPopover.jsx +102 -0
  65. package/src/app/pages/NodePage/LinkDimensionPopover.jsx +135 -0
  66. package/src/app/pages/NodePage/Loadable.jsx +9 -7
  67. package/src/app/pages/NodePage/NodeColumnTab.jsx +106 -27
  68. package/src/app/pages/NodePage/NodeGraphTab.jsx +94 -148
  69. package/src/app/pages/NodePage/NodeHistory.jsx +212 -0
  70. package/src/app/pages/NodePage/NodeInfoTab.jsx +166 -51
  71. package/src/app/pages/NodePage/NodeLineageTab.jsx +84 -0
  72. package/src/app/pages/NodePage/NodeMaterializationTab.jsx +174 -0
  73. package/src/app/pages/NodePage/NodeSQLTab.jsx +82 -0
  74. package/src/app/pages/NodePage/NodeStatus.jsx +14 -20
  75. package/src/app/pages/NodePage/NodesWithDimension.jsx +42 -0
  76. package/src/app/pages/NodePage/__tests__/ClientCodePopover.test.jsx +49 -0
  77. package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +148 -0
  78. package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +165 -0
  79. package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +591 -0
  80. package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +57 -0
  81. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +725 -0
  82. package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
  83. package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +402 -0
  84. package/src/app/pages/NodePage/index.jsx +151 -41
  85. package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
  86. package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
  87. package/src/app/pages/RegisterTablePage/index.jsx +163 -0
  88. package/src/app/pages/Root/__tests__/index.test.jsx +77 -0
  89. package/src/app/pages/Root/index.tsx +32 -4
  90. package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
  91. package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
  92. package/src/app/pages/SQLBuilderPage/index.jsx +390 -0
  93. package/src/app/providers/djclient.jsx +5 -0
  94. package/src/app/services/DJService.js +388 -22
  95. package/src/app/services/__tests__/DJService.test.jsx +609 -0
  96. package/src/mocks/mockNodes.jsx +1397 -0
  97. package/src/setupTests.ts +31 -1
  98. package/src/styles/dag.css +111 -5
  99. package/src/styles/index.css +467 -31
  100. package/src/styles/login.css +67 -0
  101. package/src/styles/node-creation.scss +197 -0
  102. package/src/styles/styles.scss +44 -0
  103. package/src/styles/styles.scss.d.ts +9 -0
  104. package/src/utils/form.jsx +23 -0
  105. package/tsconfig.json +1 -5
  106. package/webpack.config.js +29 -6
  107. package/.babelrc +0 -4
  108. package/.env.local +0 -4
  109. package/.env.production +0 -1
  110. package/.github/pull_request_template.md +0 -11
  111. package/.github/workflows/ci.yml +0 -33
  112. package/.vscode/extensions.json +0 -7
  113. package/.vscode/launch.json +0 -15
  114. package/.vscode/settings.json +0 -25
  115. package/Dockerfile +0 -7
  116. package/dist/5fa71a03d45dc2e3d61447f3013a303d.png +0 -0
  117. package/dist/index.html +0 -1
  118. package/dist/main.js +0 -23303
  119. package/dist/static/main.05a86d446163fd5f17d3.js +0 -2
  120. package/dist/static/main.05a86d446163fd5f17d3.js.LICENSE.txt +0 -98
  121. package/dist/static/main.9e53bed734dae98e5b10.js +0 -2
  122. package/dist/static/main.9e53bed734dae98e5b10.js.LICENSE.txt +0 -98
  123. package/dist/static/main.js +0 -2
  124. package/dist/static/main.js.LICENSE.txt +0 -98
  125. package/dist/static/vendor.05a86d446163fd5f17d3.js +0 -2
  126. package/dist/static/vendor.05a86d446163fd5f17d3.js.LICENSE.txt +0 -29
  127. package/dist/static/vendor.9e53bed734dae98e5b10.js +0 -2
  128. package/dist/static/vendor.9e53bed734dae98e5b10.js.LICENSE.txt +0 -29
  129. package/dist/static/vendor.js +0 -2
  130. package/dist/static/vendor.js.LICENSE.txt +0 -29
  131. package/dist/vendor.js +0 -281
  132. package/src/app/pages/ListNamespacesPage/Loadable.jsx +0 -14
  133. package/src/app/pages/ListNamespacesPage/index.jsx +0 -52
  134. package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +0 -45
  135. package/src/app/pages/NamespacePage/__tests__/index.test.tsx +0 -14
@@ -0,0 +1,135 @@
1
+ import { useContext, useState } from 'react';
2
+ import * as React from 'react';
3
+ import DJClientContext from '../../providers/djclient';
4
+ import { Form, Formik } from 'formik';
5
+ import { FormikSelect } from '../AddEditNodePage/FormikSelect';
6
+ import EditIcon from '../../icons/EditIcon';
7
+ import { displayMessageAfterSubmit } from '../../../utils/form';
8
+
9
+ export default function LinkDimensionPopover({
10
+ column,
11
+ node,
12
+ options,
13
+ onSubmit,
14
+ }) {
15
+ const djClient = useContext(DJClientContext).DataJunctionAPI;
16
+ const [popoverAnchor, setPopoverAnchor] = useState(false);
17
+ const columnDimension = column.dimension;
18
+
19
+ const handleSubmit = async (
20
+ { node, column, dimension },
21
+ { setSubmitting, setStatus },
22
+ ) => {
23
+ setSubmitting(false);
24
+ console.log('dimension', dimension, 'columnDimension', columnDimension);
25
+ if (columnDimension?.name && dimension === 'Remove') {
26
+ await unlinkDimension(node, column, columnDimension?.name, setStatus);
27
+ } else {
28
+ await linkDimension(node, column, dimension, setStatus);
29
+ }
30
+ onSubmit();
31
+ };
32
+
33
+ const linkDimension = async (node, column, dimension, setStatus) => {
34
+ const response = await djClient.linkDimension(node, column, dimension);
35
+ if (response.status === 200 || response.status === 201) {
36
+ setStatus({ success: 'Saved!' });
37
+ } else {
38
+ setStatus({
39
+ failure: `${response.json.message}`,
40
+ });
41
+ }
42
+ };
43
+
44
+ const unlinkDimension = async (node, column, currentDimension, setStatus) => {
45
+ const response = await djClient.unlinkDimension(
46
+ node,
47
+ column,
48
+ currentDimension,
49
+ );
50
+ if (response.status === 200 || response.status === 201) {
51
+ setStatus({ success: 'Removed dimension link!' });
52
+ } else {
53
+ setStatus({
54
+ failure: `${response.json.message}`,
55
+ });
56
+ }
57
+ };
58
+
59
+ return (
60
+ <>
61
+ <button
62
+ className="edit_button"
63
+ aria-label="LinkDimension"
64
+ tabIndex="0"
65
+ onClick={() => {
66
+ setPopoverAnchor(!popoverAnchor);
67
+ }}
68
+ >
69
+ <EditIcon />
70
+ </button>
71
+ <div
72
+ className="popover"
73
+ role="dialog"
74
+ aria-label="client-code"
75
+ style={{ display: popoverAnchor === false ? 'none' : 'block' }}
76
+ >
77
+ <Formik
78
+ initialValues={{
79
+ column: column.name,
80
+ node: node.name,
81
+ dimension: '',
82
+ currentDimension: column.dimension?.name,
83
+ }}
84
+ onSubmit={handleSubmit}
85
+ >
86
+ {function Render({ isSubmitting, status, setFieldValue }) {
87
+ return (
88
+ <Form>
89
+ {displayMessageAfterSubmit(status)}
90
+ <span data-testid="link-dimension">
91
+ <FormikSelect
92
+ selectOptions={[
93
+ { value: 'Remove', label: '[Remove Dimension]' },
94
+ ].concat(options)}
95
+ formikFieldName="dimension"
96
+ placeholder="Select dimension to link"
97
+ className=""
98
+ defaultValue={
99
+ column.dimension
100
+ ? {
101
+ value: column.dimension.name,
102
+ label: column.dimension.name,
103
+ }
104
+ : ''
105
+ }
106
+ />
107
+ </span>
108
+ <input
109
+ hidden={true}
110
+ name="column"
111
+ value={column.name}
112
+ readOnly={true}
113
+ />
114
+ <input
115
+ hidden={true}
116
+ name="node"
117
+ value={node.name}
118
+ readOnly={true}
119
+ />
120
+ <button
121
+ className="add_node"
122
+ type="submit"
123
+ aria-label="SaveLinkDimension"
124
+ aria-hidden="false"
125
+ >
126
+ Save
127
+ </button>
128
+ </Form>
129
+ );
130
+ }}
131
+ </Formik>
132
+ </div>
133
+ </>
134
+ );
135
+ }
@@ -5,10 +5,12 @@
5
5
  import * as React from 'react';
6
6
  import { lazyLoad } from '../../../utils/loadable';
7
7
 
8
- export const NodePage = lazyLoad(
9
- () => import('./index'),
10
- module => module.NodePage,
11
- {
12
- fallback: <div></div>,
13
- },
14
- );
8
+ export const NodePage = props => {
9
+ return lazyLoad(
10
+ () => import('./index'),
11
+ module => module.NodePage,
12
+ {
13
+ fallback: <div></div>,
14
+ },
15
+ )(props);
16
+ };
@@ -1,44 +1,123 @@
1
- import { Component } from 'react';
1
+ import { useEffect, useState } from 'react';
2
+ import ClientCodePopover from './ClientCodePopover';
3
+ import * as React from 'react';
4
+ import EditColumnPopover from './EditColumnPopover';
5
+ import LinkDimensionPopover from './LinkDimensionPopover';
6
+ import { labelize } from '../../../utils/form';
2
7
 
3
- export default class NodeColumnTab extends Component {
4
- columnList = node => {
5
- return node.columns.map(col => (
6
- <tr>
7
- <td className="text-start">{col.name}</td>
8
+ export default function NodeColumnTab({ node, djClient }) {
9
+ const [attributes, setAttributes] = useState([]);
10
+ const [dimensions, setDimensions] = useState([]);
11
+ const [columns, setColumns] = useState([]);
12
+ useEffect(() => {
13
+ const fetchData = async () => {
14
+ setColumns(await djClient.columns(node));
15
+ };
16
+ fetchData().catch(console.error);
17
+ }, [djClient, node]);
18
+
19
+ useEffect(() => {
20
+ const fetchData = async () => {
21
+ const attributes = await djClient.attributes();
22
+ const options = attributes.map(attr => {
23
+ return { value: attr.name, label: labelize(attr.name) };
24
+ });
25
+ setAttributes(options);
26
+ };
27
+ fetchData().catch(console.error);
28
+ }, [djClient]);
29
+
30
+ useEffect(() => {
31
+ const fetchData = async () => {
32
+ const dimensions = await djClient.dimensions();
33
+ const options = dimensions.map(name => {
34
+ return { value: name, label: name };
35
+ });
36
+ setDimensions(options);
37
+ };
38
+ fetchData().catch(console.error);
39
+ }, [djClient]);
40
+
41
+ const showColumnAttributes = col => {
42
+ return col.attributes.map((attr, idx) => (
43
+ <span
44
+ className="node_type__dimension badge node_type"
45
+ key={`col-attr-${col.name}-${idx}`}
46
+ >
47
+ {attr.attribute_type.name.replace(/_/, ' ')}
48
+ </span>
49
+ ));
50
+ };
51
+
52
+ const columnList = columns => {
53
+ return columns.map(col => (
54
+ <tr key={col.name}>
55
+ <td
56
+ className="text-start"
57
+ role="columnheader"
58
+ aria-label="ColumnName"
59
+ aria-hidden="false"
60
+ >
61
+ {col.name}
62
+ </td>
8
63
  <td>
9
- <span className="node_type__transform badge node_type">
64
+ <span
65
+ className="node_type__transform badge node_type"
66
+ role="columnheader"
67
+ aria-label="ColumnType"
68
+ aria-hidden="false"
69
+ >
10
70
  {col.type}
11
71
  </span>
12
72
  </td>
13
- <td>{col.dimension ? col.dimension.name : ''}</td>
14
73
  <td>
15
- {col.attributes.find(
16
- attr => attr.attribute_type.name === 'dimension',
17
- ) ? (
18
- <span className="node_type__dimension badge node_type">
19
- dimensional
20
- </span>
74
+ {col.dimension !== undefined && col.dimension !== null ? (
75
+ <>
76
+ <a href={`/nodes/${col.dimension.name}`}>{col.dimension.name}</a>
77
+ <ClientCodePopover code={col.clientCode} />
78
+ </>
21
79
  ) : (
22
80
  ''
23
- )}
81
+ )}{' '}
82
+ <LinkDimensionPopover
83
+ column={col}
84
+ node={node}
85
+ options={dimensions}
86
+ onSubmit={async () => {
87
+ const res = await djClient.node(node.name);
88
+ setColumns(res.columns);
89
+ }}
90
+ />
91
+ </td>
92
+ <td>
93
+ {showColumnAttributes(col)}
94
+ <EditColumnPopover
95
+ column={col}
96
+ node={node}
97
+ options={attributes}
98
+ onSubmit={async () => {
99
+ const res = await djClient.node(node.name);
100
+ setColumns(res.columns);
101
+ }}
102
+ />
24
103
  </td>
25
104
  </tr>
26
105
  ));
27
106
  };
28
107
 
29
- render() {
30
- return (
31
- <div className="table-responsive">
32
- <table className="card-inner-table table">
33
- <thead className="fs-7 fw-bold text-gray-400 border-bottom-0">
108
+ return (
109
+ <div className="table-responsive">
110
+ <table className="card-inner-table table">
111
+ <thead className="fs-7 fw-bold text-gray-400 border-bottom-0">
112
+ <tr>
34
113
  <th className="text-start">Column</th>
35
114
  <th>Type</th>
36
- <th>Dimension</th>
115
+ <th>Linked Dimension</th>
37
116
  <th>Attributes</th>
38
- </thead>
39
- {this.columnList(this.props.node)}
40
- </table>
41
- </div>
42
- );
43
- }
117
+ </tr>
118
+ </thead>
119
+ <tbody>{columnList(columns)}</tbody>
120
+ </table>
121
+ </div>
122
+ );
44
123
  }
@@ -1,166 +1,112 @@
1
- import React, { useCallback, 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 { DataJunctionAPI } from '../../services/DJService';
16
- import dagre from 'dagre';
6
+ import DJClientContext from '../../providers/djclient';
7
+ import LayoutFlow from '../../components/djgraph/LayoutFlow';
17
8
 
18
9
  const NodeLineage = djNode => {
19
- const nodeTypes = useMemo(() => ({ DJNode: DJNode }), []);
10
+ const djClient = useContext(DJClientContext).DataJunctionAPI;
20
11
 
21
- const [nodes, setNodes, onNodesChange] = useNodesState([]);
22
- const [edges, setEdges, onEdgesChange] = useEdgesState([]);
23
-
24
- const minimapStyle = {
25
- height: 100,
26
- width: 150,
27
- };
28
- const dagreGraph = new dagre.graphlib.Graph();
29
- dagreGraph.setDefaultEdgeLabel(() => ({}));
30
-
31
- const setElementsLayout = (
32
- nodes,
33
- edges,
34
- direction = 'LR',
35
- nodeWidth = 800,
36
- nodeHeight = 150,
37
- ) => {
38
- const isHorizontal = direction === 'TB';
39
- dagreGraph.setGraph({ rankdir: direction });
40
-
41
- nodes.forEach(node => {
42
- dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
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 column_names = node.columns.map(col => {
19
+ return { name: col.name, type: col.type };
43
20
  });
44
-
45
- edges.forEach(edge => {
46
- dagreGraph.setEdge(edge.source, edge.target);
47
- });
48
-
49
- dagre.layout(dagreGraph);
50
-
51
- nodes.forEach(node => {
52
- const nodeWithPosition = dagreGraph.node(node.id);
53
- node.targetPosition = isHorizontal ? 'left' : 'top';
54
- node.sourcePosition = isHorizontal ? 'right' : 'bottom';
55
- node.position = {
56
- x: nodeWithPosition.x - nodeWidth / 2,
57
- y: nodeWithPosition.y - nodeHeight / 2,
58
- };
59
- return node;
60
- });
61
-
62
- return { nodes, edges };
21
+ return {
22
+ id: String(node.name),
23
+ type: 'DJNode',
24
+ data: {
25
+ label:
26
+ node.table !== null
27
+ ? String(node.schema_ + '.' + node.table)
28
+ : 'default.' + node.name,
29
+ table: node.table,
30
+ name: String(node.name),
31
+ display_name: String(node.display_name),
32
+ type: node.type,
33
+ primary_key: primary_key,
34
+ column_names: column_names,
35
+ is_current: node.name === djNode.djNode.name,
36
+ },
37
+ };
63
38
  };
64
39
 
65
- useEffect(() => {
66
- const dagFetch = async () => {
67
- let upstreams = await DataJunctionAPI.upstreams(djNode.djNode.name);
68
- let downstreams = await DataJunctionAPI.downstreams(djNode.djNode.name);
69
- var djNodes = [djNode.djNode];
70
- for (const iterable of [upstreams, downstreams]) {
71
- for (const item of iterable) {
72
- djNodes.push(item);
73
- }
74
- }
75
- let edges = [];
76
- djNodes.forEach(obj => {
77
- obj.parents.forEach(parent => {
78
- if (parent.name) {
79
- edges.push({
80
- id: obj.name + '-' + parent.name,
81
- target: obj.name,
82
- source: parent.name,
83
- animated: true,
84
- markerEnd: {
85
- type: MarkerType.Arrow,
86
- },
87
- });
88
- }
89
- });
90
-
91
- obj.columns.forEach(col => {
92
- if (col.dimension) {
93
- edges.push({
94
- id: obj.name + '-' + col.dimension.name,
95
- target: obj.name,
96
- source: col.dimension.name,
97
- draggable: true,
98
- });
99
- }
100
- });
101
- });
102
- const nodes = djNodes.map(node => {
103
- const primary_key = node.columns
104
- .filter(col =>
105
- col.attributes.some(
106
- attr => attr.attribute_type.name === 'primary_key',
107
- ),
108
- )
109
- .map(col => col.name);
110
- const column_names = node.columns.map(col => {
111
- return { name: col.name, type: col.type };
112
- });
40
+ const dimensionEdges = node => {
41
+ return node.columns
42
+ .filter(col => col.dimension)
43
+ .map(col => {
113
44
  return {
114
- id: String(node.name),
115
- type: 'DJNode',
116
- data: {
117
- label:
118
- node.table !== null
119
- ? String(node.schema_ + '.' + node.table)
120
- : String(node.name),
121
- table: node.table,
122
- name: String(node.name),
123
- display_name: String(node.display_name),
124
- type: node.type,
125
- primary_key: primary_key,
126
- column_names: column_names,
127
- // dimensions: dimensions,
45
+ id: col.dimension.name + '->' + node.name + '.' + col.name,
46
+ source: col.dimension.name,
47
+ sourceHandle: col.dimension.name,
48
+ target: node.name,
49
+ targetHandle: node.name + '.' + col.name,
50
+ draggable: true,
51
+ markerStart: {
52
+ type: MarkerType.Arrow,
53
+ width: 20,
54
+ height: 20,
55
+ color: '#b0b9c2',
56
+ },
57
+ style: {
58
+ strokeWidth: 3,
59
+ stroke: '#b0b9c2',
128
60
  },
129
- // parentNode: [node.name.split(".").slice(-2, -1)],
130
- // extent: 'parent',
131
61
  };
132
62
  });
133
- console.log(djNodes);
134
- setNodes(nodes);
135
- setEdges(edges);
136
- setElementsLayout(nodes, edges);
137
- };
63
+ };
138
64
 
139
- dagFetch();
140
- }, []);
65
+ const parentEdges = node => {
66
+ return node.parents
67
+ .filter(parent => parent.name)
68
+ .map(parent => {
69
+ return {
70
+ id: node.name + '-' + parent.name,
71
+ source: parent.name,
72
+ sourceHandle: parent.name,
73
+ target: node.name,
74
+ targetHandle: node.name,
75
+ animated: true,
76
+ markerEnd: {
77
+ type: MarkerType.Arrow,
78
+ },
79
+ style: {
80
+ strokeWidth: 3,
81
+ stroke: '#b0b9c2',
82
+ },
83
+ };
84
+ });
85
+ };
141
86
 
142
- const onConnect = useCallback(
143
- params => setEdges(eds => addEdge(params, eds)),
144
- [],
145
- );
87
+ const dagFetch = async (getLayoutedElements, setNodes, setEdges) => {
88
+ let related_nodes = await djClient.node_dag(djNode.djNode.name);
89
+ var djNodes = [djNode.djNode];
90
+ for (const iterable of [related_nodes]) {
91
+ for (const item of iterable) {
92
+ if (item.type !== 'cube') {
93
+ djNodes.push(item);
94
+ }
95
+ }
96
+ }
97
+ let edges = [];
98
+ djNodes.forEach(node => {
99
+ edges = edges.concat(parentEdges(node));
100
+ edges = edges.concat(dimensionEdges(node));
101
+ });
102
+ const nodes = djNodes.map(node => createNode(node));
146
103
 
147
- return (
148
- <div style={{ height: '600px' }}>
149
- <ReactFlow
150
- nodes={nodes}
151
- edges={edges}
152
- nodeTypes={nodeTypes}
153
- onNodesChange={onNodesChange}
154
- onEdgesChange={onEdgesChange}
155
- onConnect={onConnect}
156
- snapToGrid={true}
157
- fitView
158
- >
159
- <MiniMap style={minimapStyle} zoomable pannable />
160
- <Controls />
161
- <Background color="#aaa" gap={16} />
162
- </ReactFlow>
163
- </div>
164
- );
104
+ // use dagre to determine the position of the parents (the DJ nodes)
105
+ // the positions of the columns are relative to each DJ node
106
+ getLayoutedElements(nodes, edges);
107
+ setNodes(nodes);
108
+ setEdges(edges);
109
+ };
110
+ return LayoutFlow(djNode, dagFetch);
165
111
  };
166
112
  export default NodeLineage;