datajunction-ui 0.0.1-rc.4 → 0.0.1-rc.6

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.
@@ -2,9 +2,9 @@ name: CI/CD
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [master]
5
+ branches: [main]
6
6
  pull_request:
7
- branches: [master]
7
+ branches: [main]
8
8
 
9
9
  jobs:
10
10
  build:
@@ -19,7 +19,7 @@ jobs:
19
19
  uses: actions/checkout@v2
20
20
 
21
21
  - name: Set up Node.js ${{ matrix.node-version }}
22
- uses: actions/setup-node@v3.6.
22
+ uses: actions/setup-node@v3
23
23
  with:
24
24
  node-version: ${{ matrix.node-version }}
25
25
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datajunction-ui",
3
- "version": "0.0.1-rc.4",
3
+ "version": "0.0.1-rc.6",
4
4
  "description": "DataJunction Metrics Platform UI",
5
5
  "module": "src/index.tsx",
6
6
  "repository": {
@@ -38,9 +38,13 @@
38
38
  "@types/testing-library__jest-dom": "^5.14.5",
39
39
  "@types/webpack": "^5.28.0",
40
40
  "@types/webpack-env": "^1.18.0",
41
+ "babel-loader": "9.1.2",
41
42
  "chalk": "4.1.2",
42
43
  "cross-env": "7.0.3",
44
+ "css-loader": "6.7.3",
43
45
  "dagre": "^0.8.5",
46
+ "datajunction": "0.0.1-rc.0",
47
+ "file-loader": "6.2.0",
44
48
  "fontfaceobserver": "2.3.0",
45
49
  "husky": "8.0.1",
46
50
  "i18next": "21.9.2",
@@ -71,6 +75,7 @@
71
75
  "serve": "14.0.1",
72
76
  "shelljs": "0.8.5",
73
77
  "sql-formatter": "^12.2.0",
78
+ "style-loader": "3.3.2",
74
79
  "stylelint": "14.12.0",
75
80
  "stylelint-config-recommended": "9.0.0",
76
81
  "ts-loader": "9.4.2",
@@ -78,7 +83,8 @@
78
83
  "typescript": "4.6.4",
79
84
  "web-vitals": "2.1.4",
80
85
  "webpack": "5.81.0",
81
- "webpack-cli": "5.0.2"
86
+ "webpack-cli": "5.0.2",
87
+ "webpack-dev-server": "4.13.3"
82
88
  },
83
89
  "scripts": {
84
90
  "webpack-start": "webpack-dev-server --open",
@@ -14,30 +14,100 @@ exports[`<App /> should render and match the snapshot 1`] = `
14
14
  name="description"
15
15
  />
16
16
  </Helmet>
17
- <Routes>
18
- <Route
19
- element={<Unknown />}
20
- path="/"
21
- >
22
- <React.Fragment>
23
- <Route
24
- element={<Unknown />}
25
- path="nodes/:name"
26
- />
27
- <Route
28
- element={<ListNamespacesPage />}
29
- path="namespaces"
30
- />
31
- <Route
32
- element={<Unknown />}
33
- path="namespaces/:namespace"
34
- />
35
- </React.Fragment>
36
- </Route>
37
- <Route
38
- element={<Unknown />}
39
- path="*"
40
- />
41
- </Routes>
17
+ <Context.Provider
18
+ value={
19
+ Object {
20
+ "DataJunctionAPI": Object {
21
+ "dag": [Function],
22
+ "downstreams": [Function],
23
+ "lineage": [Function],
24
+ "metric": [Function],
25
+ "namespace": [Function],
26
+ "namespaces": [Function],
27
+ "node": [Function],
28
+ "upstreams": [Function],
29
+ },
30
+ }
31
+ }
32
+ >
33
+ <Routes>
34
+ <Route
35
+ element={<Unknown />}
36
+ path="/"
37
+ >
38
+ <React.Fragment>
39
+ <Route
40
+ path="nodes"
41
+ >
42
+ <Route
43
+ element={
44
+ <NodePage
45
+ djClient={
46
+ Object {
47
+ "dag": [Function],
48
+ "downstreams": [Function],
49
+ "lineage": [Function],
50
+ "metric": [Function],
51
+ "namespace": [Function],
52
+ "namespaces": [Function],
53
+ "node": [Function],
54
+ "upstreams": [Function],
55
+ }
56
+ }
57
+ />
58
+ }
59
+ path=":name"
60
+ />
61
+ </Route>
62
+ <Route
63
+ element={
64
+ <ListNamespacesPage
65
+ djClient={
66
+ Object {
67
+ "dag": [Function],
68
+ "downstreams": [Function],
69
+ "lineage": [Function],
70
+ "metric": [Function],
71
+ "namespace": [Function],
72
+ "namespaces": [Function],
73
+ "node": [Function],
74
+ "upstreams": [Function],
75
+ }
76
+ }
77
+ />
78
+ }
79
+ path="/"
80
+ />
81
+ <Route
82
+ path="namespaces"
83
+ >
84
+ <Route
85
+ element={
86
+ <NamespacePage
87
+ djClient={
88
+ Object {
89
+ "dag": [Function],
90
+ "downstreams": [Function],
91
+ "lineage": [Function],
92
+ "metric": [Function],
93
+ "namespace": [Function],
94
+ "namespaces": [Function],
95
+ "node": [Function],
96
+ "upstreams": [Function],
97
+ }
98
+ }
99
+ />
100
+ }
101
+ path=":namespace"
102
+ />
103
+ </Route>
104
+ </React.Fragment>
105
+ </Route>
106
+ <Route
107
+ element={<Unknown />}
108
+ path="*"
109
+ />
110
+ </Routes>
111
+ </Context.Provider>
42
112
  </BrowserRouter>
43
113
  `;
@@ -7,15 +7,8 @@ export default class Tab extends Component {
7
7
  <div className={selectedTab === id ? 'col active' : 'col'}>
8
8
  <div className="header-tabs nav-overflow nav nav-tabs">
9
9
  <div className="nav-item">
10
- <button
11
- id={id}
12
- role="button"
13
- className="nav-link"
14
- tabIndex="0"
15
- onClick={onClick}
16
- >
10
+ <button id={id} className="nav-link" tabIndex="0" onClick={onClick}>
17
11
  {this.props.name}
18
- {/*<span className="rounded-pill badge bg-secondary-soft">823</span>*/}
19
12
  </button>
20
13
  </div>
21
14
  </div>
@@ -61,12 +61,12 @@ export function DJNode({ id, data }) {
61
61
  <td style={{ textAlign: 'right' }}>{col.type}</td>
62
62
  </tr>
63
63
  ));
64
- const dimensionsRenderer = data =>
65
- data.dimensions.map(dim => (
66
- <tr>
67
- <td>{dim}</td>
68
- </tr>
69
- ));
64
+ // const dimensionsRenderer = data =>
65
+ // data.dimensions.map(dim => (
66
+ // <tr>
67
+ // <td>{dim}</td>
68
+ // </tr>
69
+ // ));
70
70
 
71
71
  return (
72
72
  <>
package/src/app/index.tsx CHANGED
@@ -12,8 +12,13 @@ import { NodePage } from './pages/NodePage/Loadable';
12
12
  import { NotFoundPage } from './pages/NotFoundPage/Loadable';
13
13
  import { Root } from './pages/Root/Loadable';
14
14
  import { ListNamespacesPage } from './pages/ListNamespacesPage';
15
+ import { DataJunctionAPI } from './services/DJService';
16
+
17
+ const DJClientContext = React.createContext({ DataJunctionAPI });
15
18
 
16
19
  export function App() {
20
+ const DJClient = React.useContext(DJClientContext);
21
+
17
22
  return (
18
23
  <BrowserRouter>
19
24
  <Helmet
@@ -25,7 +30,6 @@ export function App() {
25
30
  content="DataJunction serves as a semantic layer to help manage metrics"
26
31
  />
27
32
  </Helmet>
28
-
29
33
  <Routes>
30
34
  <Route
31
35
  path="/"
@@ -33,14 +37,14 @@ export function App() {
33
37
  children={
34
38
  <>
35
39
  <Route path="nodes" key="nodes">
36
- <Route path=":name" element={<NodePage />} />
40
+ <Route path=":name" element={<NodePage djClient={ DJClient.DataJunctionAPI } />} />
37
41
  </Route>
38
42
 
39
- <Route path="/" element={<ListNamespacesPage />} key="index" />
43
+ <Route path="/" element={<ListNamespacesPage djClient={ DJClient.DataJunctionAPI }/>} key="index" />
40
44
  <Route path="namespaces">
41
45
  <Route
42
46
  path=":namespace"
43
- element={<NamespacePage />}
47
+ element={<NamespacePage djClient={ DJClient.DataJunctionAPI }/>}
44
48
  key="namespaces"
45
49
  />
46
50
  </Route>
@@ -52,3 +56,5 @@ export function App() {
52
56
  </BrowserRouter>
53
57
  );
54
58
  }
59
+
60
+ export { DJClientContext };
@@ -1,22 +1,24 @@
1
1
  import * as React from 'react';
2
2
  import { useEffect, useState } from 'react';
3
- import { DataJunctionAPI } from '../../services/DJService';
4
3
  import NamespaceHeader from '../../components/NamespaceHeader';
4
+ import { DataJunctionAPI } from '../../services/DJService';
5
+ // const datajunction = require('datajunction');
6
+ // const dj = new datajunction.DJClient('http://localhost:8000');
5
7
 
6
- export function ListNamespacesPage() {
8
+ export function ListNamespacesPage({ djClient }) {
7
9
  const [state, setState] = useState({
8
10
  namespaces: [],
9
11
  });
10
12
 
11
13
  useEffect(() => {
12
14
  const fetchData = async () => {
13
- const namespaces = await DataJunctionAPI.namespaces();
15
+ const namespaces = await djClient.namespaces.get();
14
16
  setState({
15
17
  namespaces: namespaces,
16
18
  });
17
19
  };
18
20
  fetchData().catch(console.error);
19
- }, []);
21
+ }, [djClient.namespaces]);
20
22
 
21
23
  const namespacesList = state.namespaces.map(node => (
22
24
  <tr>
@@ -50,3 +52,7 @@ export function ListNamespacesPage() {
50
52
  </>
51
53
  );
52
54
  }
55
+
56
+ ListNamespacesPage.defaultProps = {
57
+ djClient: DataJunctionAPI,
58
+ };
@@ -5,10 +5,12 @@
5
5
  import * as React from 'react';
6
6
  import { lazyLoad } from '../../../utils/loadable';
7
7
 
8
- export const NamespacePage = lazyLoad(
9
- () => import('./index'),
10
- module => module.NamespacePage,
11
- {
12
- fallback: <div></div>,
13
- },
14
- );
8
+ export const NamespacePage = props => {
9
+ return lazyLoad(
10
+ () => import('./index'),
11
+ module => module.NamespacePage,
12
+ {
13
+ fallback: <div></div>,
14
+ },
15
+ )(props);
16
+ };
@@ -5,16 +5,7 @@ import { DataJunctionAPI } from '../../services/DJService';
5
5
  import NamespaceHeader from '../../components/NamespaceHeader';
6
6
  import NodeStatus from '../NodePage/NodeStatus';
7
7
 
8
- export async function loader({ params }) {
9
- const djNode = await DataJunctionAPI.node(params.name);
10
- if (djNode.type === 'metric') {
11
- const metricNode = await DataJunctionAPI.metric(params.name);
12
- djNode.dimensions = metricNode.dimensions;
13
- }
14
- return djNode;
15
- }
16
-
17
- export function NamespacePage() {
8
+ export function NamespacePage({ djClient = DataJunctionAPI }) {
18
9
  const { namespace } = useParams();
19
10
 
20
11
  const [state, setState] = useState({
@@ -24,9 +15,9 @@ export function NamespacePage() {
24
15
 
25
16
  useEffect(() => {
26
17
  const fetchData = async () => {
27
- const djNodes = await DataJunctionAPI.namespace(namespace);
18
+ const djNodes = await djClient.namespace(namespace);
28
19
  const nodes = djNodes.map(node => {
29
- return DataJunctionAPI.node(node);
20
+ return djClient.node(node);
30
21
  });
31
22
  const foundNodes = await Promise.all(nodes);
32
23
  setState({
@@ -35,7 +26,7 @@ export function NamespacePage() {
35
26
  });
36
27
  };
37
28
  fetchData().catch(console.error);
38
- }, [namespace]);
29
+ }, [djClient, namespace]);
39
30
 
40
31
  const nodesList = state.nodes.map(node => (
41
32
  <tr>
@@ -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
+ };
@@ -12,10 +12,9 @@ import ReactFlow, {
12
12
  import '../../../styles/dag.css';
13
13
  import 'reactflow/dist/style.css';
14
14
  import DJNode from '../../components/djgraph/DJNode';
15
- import { DataJunctionAPI } from '../../services/DJService';
16
15
  import dagre from 'dagre';
17
16
 
18
- const NodeLineage = djNode => {
17
+ const NodeLineage = (djNode, djClient) => {
19
18
  const nodeTypes = useMemo(() => ({ DJNode: DJNode }), []);
20
19
 
21
20
  const [nodes, setNodes, onNodesChange] = useNodesState([]);
@@ -25,47 +24,48 @@ const NodeLineage = djNode => {
25
24
  height: 100,
26
25
  width: 150,
27
26
  };
28
- const dagreGraph = new dagre.graphlib.Graph();
29
- dagreGraph.setDefaultEdgeLabel(() => ({}));
30
27
 
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 });
43
- });
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 };
63
- };
28
+ const dagreGraph = useMemo(() => new dagre.graphlib.Graph(), []);
29
+ dagreGraph.setDefaultEdgeLabel(() => ({}));
64
30
 
65
31
  useEffect(() => {
32
+ const setElementsLayout = (
33
+ nodes,
34
+ edges,
35
+ direction = 'LR',
36
+ nodeWidth = 800,
37
+ nodeHeight = 150,
38
+ ) => {
39
+ const isHorizontal = direction === 'TB';
40
+ dagreGraph.setGraph({ rankdir: direction });
41
+
42
+ nodes.forEach(node => {
43
+ dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
44
+ });
45
+
46
+ edges.forEach(edge => {
47
+ dagreGraph.setEdge(edge.source, edge.target);
48
+ });
49
+
50
+ dagre.layout(dagreGraph);
51
+
52
+ nodes.forEach(node => {
53
+ const nodeWithPosition = dagreGraph.node(node.id);
54
+ node.targetPosition = isHorizontal ? 'left' : 'top';
55
+ node.sourcePosition = isHorizontal ? 'right' : 'bottom';
56
+ node.position = {
57
+ x: nodeWithPosition.x - nodeWidth / 2,
58
+ y: nodeWithPosition.y - nodeHeight / 2,
59
+ };
60
+ return node;
61
+ });
62
+
63
+ return { nodes, edges };
64
+ };
65
+
66
66
  const dagFetch = async () => {
67
- let upstreams = await DataJunctionAPI.upstreams(djNode.djNode.name);
68
- let downstreams = await DataJunctionAPI.downstreams(djNode.djNode.name);
67
+ let upstreams = await djClient.upstreams(djNode.djNode.name);
68
+ let downstreams = await djClient.downstreams(djNode.djNode.name);
69
69
  var djNodes = [djNode.djNode];
70
70
  for (const iterable of [upstreams, downstreams]) {
71
71
  for (const item of iterable) {
@@ -117,7 +117,7 @@ const NodeLineage = djNode => {
117
117
  label:
118
118
  node.table !== null
119
119
  ? String(node.schema_ + '.' + node.table)
120
- : String(node.name),
120
+ : 'default.' + node.name,
121
121
  table: node.table,
122
122
  name: String(node.name),
123
123
  display_name: String(node.display_name),
@@ -137,11 +137,11 @@ const NodeLineage = djNode => {
137
137
  };
138
138
 
139
139
  dagFetch();
140
- }, []);
140
+ }, [dagreGraph, djNode.djNode, setEdges, setNodes]);
141
141
 
142
142
  const onConnect = useCallback(
143
143
  params => setEdges(eds => addEdge(params, eds)),
144
- [],
144
+ [setEdges],
145
145
  );
146
146
 
147
147
  return (
@@ -1,14 +1,14 @@
1
1
  import * as React from 'react';
2
2
  import { useParams } from 'react-router-dom';
3
3
  import { useEffect, useState } from 'react';
4
- import { DataJunctionAPI } from '../../services/DJService';
5
4
  import Tab from '../../components/Tab';
6
5
  import NamespaceHeader from '../../components/NamespaceHeader';
7
6
  import NodeInfoTab from './NodeInfoTab';
8
7
  import NodeColumnTab from './NodeColumnTab';
9
8
  import NodeLineage from './NodeGraphTab';
9
+ import { DataJunctionAPI } from '../../services/DJService';
10
10
 
11
- export function NodePage() {
11
+ export function NodePage({ djClient = DataJunctionAPI}) {
12
12
  const [state, setState] = useState({
13
13
  selectedTab: 0,
14
14
  });
@@ -35,11 +35,11 @@ export function NodePage() {
35
35
 
36
36
  useEffect(() => {
37
37
  const fetchData = async () => {
38
- const data = await DataJunctionAPI.node(name);
38
+ const data = await djClient.node(name);
39
39
  setNode(data);
40
40
  };
41
41
  fetchData().catch(console.error);
42
- }, [name]);
42
+ }, [djClient, name]);
43
43
 
44
44
  const TabsJson = [
45
45
  {
@@ -66,7 +66,7 @@ export function NodePage() {
66
66
  tabToDisplay = <NodeColumnTab node={node} />;
67
67
  break;
68
68
  case 2:
69
- tabToDisplay = <NodeLineage djNode={node} />;
69
+ tabToDisplay = <NodeLineage djNode={node} djClient={djClient} />;
70
70
  break;
71
71
  default:
72
72
  tabToDisplay = <NodeInfoTab node={node} />;
@@ -379,8 +379,8 @@ tbody th {
379
379
  }
380
380
 
381
381
  .node_type__cube {
382
- background-color: #c2180750 !important;
383
- color: #c21807;
382
+ background-color: #dbafff !important;
383
+ color: #580076;
384
384
  }
385
385
 
386
386
  .status__valid {
@@ -498,8 +498,8 @@ pre {
498
498
  flex-grow: 0 !important;
499
499
  }
500
500
  .logo img {
501
- padding: 10px;
502
- margin-bottom: -1.2rem;
501
+ padding: 15px;
502
+ margin-bottom: 0.2rem;
503
503
  }
504
504
 
505
505
  .menu-lg-row > .menu-item {
package/webpack.config.js CHANGED
@@ -1,3 +1,4 @@
1
+ const webpack = require('webpack');
1
2
  const path = require('path');
2
3
  const HtmlWebpackPlugin = require('html-webpack-plugin');
3
4
  // const MiniCssExtractPlugin = require('mini-css-extract-plugin');
@@ -37,6 +38,13 @@ module.exports = {
37
38
  fs: false,
38
39
  os: false,
39
40
  module: false,
41
+ http: false,
42
+ tls: false,
43
+ https: false,
44
+ url: false,
45
+ browser: false,
46
+ net: false,
47
+ process: false,
40
48
  },
41
49
  },
42
50
  module: {
@@ -90,6 +98,9 @@ module.exports = {
90
98
  new HtmlWebpackPlugin({
91
99
  template: path.resolve(__dirname, 'public', 'index.html'),
92
100
  }),
101
+ new webpack.DefinePlugin({
102
+ REACT_APP_DJ_URL: 'http://localhost:8000',
103
+ }),
93
104
  // new MiniCssExtractPlugin({
94
105
  // filename: './styles/index.css',
95
106
  // }),