datajunction-ui 0.0.1-rc.0

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 (71) hide show
  1. package/.env +1 -0
  2. package/.env.local +4 -0
  3. package/.env.production +1 -0
  4. package/.eslintrc.js +20 -0
  5. package/.gitattributes +201 -0
  6. package/.github/pull_request_template.md +11 -0
  7. package/.github/workflows/ci.yml +33 -0
  8. package/.husky/pre-commit +6 -0
  9. package/.nvmrc +1 -0
  10. package/.prettierignore +4 -0
  11. package/.prettierrc +9 -0
  12. package/.stylelintrc +7 -0
  13. package/.vscode/extensions.json +8 -0
  14. package/.vscode/launch.json +15 -0
  15. package/.vscode/settings.json +25 -0
  16. package/Dockerfile +6 -0
  17. package/LICENSE +22 -0
  18. package/README.md +10 -0
  19. package/internals/testing/loadable.mock.tsx +6 -0
  20. package/package.json +150 -0
  21. package/public/favicon.ico +0 -0
  22. package/public/index.html +29 -0
  23. package/public/manifest.json +15 -0
  24. package/public/robots.txt +3 -0
  25. package/src/app/__tests__/__snapshots__/index.test.tsx.snap +45 -0
  26. package/src/app/__tests__/index.test.tsx +14 -0
  27. package/src/app/components/ListGroupItem.jsx +17 -0
  28. package/src/app/components/NamespaceHeader.jsx +40 -0
  29. package/src/app/components/Tab.jsx +26 -0
  30. package/src/app/components/__tests__/ListGroupItem.test.tsx +16 -0
  31. package/src/app/components/__tests__/NamespaceHeader.test.jsx +14 -0
  32. package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +26 -0
  33. package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +63 -0
  34. package/src/app/components/djgraph/DJNode.jsx +111 -0
  35. package/src/app/components/djgraph/__tests__/DJNode.test.tsx +24 -0
  36. package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +73 -0
  37. package/src/app/index.tsx +53 -0
  38. package/src/app/pages/ListNamespacesPage/Loadable.jsx +23 -0
  39. package/src/app/pages/ListNamespacesPage/index.jsx +53 -0
  40. package/src/app/pages/NamespacePage/Loadable.jsx +23 -0
  41. package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +45 -0
  42. package/src/app/pages/NamespacePage/__tests__/index.test.tsx +14 -0
  43. package/src/app/pages/NamespacePage/index.jsx +93 -0
  44. package/src/app/pages/NodePage/Loadable.jsx +23 -0
  45. package/src/app/pages/NodePage/NodeColumnTab.jsx +44 -0
  46. package/src/app/pages/NodePage/NodeGraphTab.jsx +160 -0
  47. package/src/app/pages/NodePage/NodeInfoTab.jsx +87 -0
  48. package/src/app/pages/NodePage/NodeStatus.jsx +34 -0
  49. package/src/app/pages/NodePage/index.jsx +100 -0
  50. package/src/app/pages/NotFoundPage/Loadable.tsx +14 -0
  51. package/src/app/pages/NotFoundPage/P.ts +8 -0
  52. package/src/app/pages/NotFoundPage/__tests__/__snapshots__/index.test.tsx.snap +61 -0
  53. package/src/app/pages/NotFoundPage/__tests__/index.test.tsx +21 -0
  54. package/src/app/pages/NotFoundPage/index.tsx +45 -0
  55. package/src/app/pages/Root/Loadable.tsx +23 -0
  56. package/src/app/pages/Root/assets/dj-logo.png +0 -0
  57. package/src/app/pages/Root/index.tsx +42 -0
  58. package/src/app/services/DJService.js +124 -0
  59. package/src/index.tsx +47 -0
  60. package/src/react-app-env.d.ts +4 -0
  61. package/src/reportWebVitals.ts +15 -0
  62. package/src/setupTests.ts +8 -0
  63. package/src/styles/dag-styles.ts +117 -0
  64. package/src/styles/global-styles.ts +588 -0
  65. package/src/styles/index.css +546 -0
  66. package/src/utils/__tests__/__snapshots__/loadable.test.tsx.snap +17 -0
  67. package/src/utils/__tests__/loadable.test.tsx +53 -0
  68. package/src/utils/__tests__/request.test.ts +82 -0
  69. package/src/utils/loadable.tsx +30 -0
  70. package/src/utils/request.ts +54 -0
  71. package/tsconfig.json +31 -0
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Asynchronously loads the component for the root page
3
+ */
4
+
5
+ import * as React from 'react';
6
+ import { lazyLoad } from 'utils/loadable';
7
+ import styled from 'styled-components/macro';
8
+
9
+ const LoadingWrapper = styled.div`
10
+ width: 100%;
11
+ height: 100vh;
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ `;
16
+
17
+ export const Root = lazyLoad(
18
+ () => import('./index'),
19
+ module => module.Root,
20
+ {
21
+ fallback: <LoadingWrapper></LoadingWrapper>,
22
+ },
23
+ );
@@ -0,0 +1,42 @@
1
+ import { Outlet } from 'react-router-dom';
2
+ import logo from './assets/dj-logo.png';
3
+ import { Helmet } from 'react-helmet-async';
4
+
5
+ export function Root() {
6
+ return (
7
+ <>
8
+ <Helmet>
9
+ <title>DataJunction</title>
10
+ <meta
11
+ name="description"
12
+ content="DataJunction Metrics Platform Webapp"
13
+ />
14
+ </Helmet>
15
+ <div className="container d-flex align-items-center justify-content-between">
16
+ <div className="header">
17
+ <div className="logo">
18
+ <h2>
19
+ <img src={logo} alt="DJ Logo" width="15%" />
20
+ DataJunction
21
+ </h2>
22
+ </div>
23
+ <div className="menu">
24
+ <div className="menu-item here menu-here-bg menu-lg-down-accordion me-0 me-lg-2 fw-semibold">
25
+ <span className="menu-link">
26
+ <span className="menu-title">
27
+ <a href="/">Explore</a>
28
+ </span>
29
+ </span>
30
+ <span className="menu-link">
31
+ <span className="menu-title">
32
+ <a href="/">Help</a>
33
+ </span>
34
+ </span>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ <Outlet />
40
+ </>
41
+ );
42
+ }
@@ -0,0 +1,124 @@
1
+ import { MarkerType } from 'reactflow';
2
+
3
+ const DJ_URL = 'http://localhost:8000'; //process.env.REACT_APP_DJ_URL;
4
+
5
+ export const DataJunctionAPI = {
6
+ node: async function (name) {
7
+ const data = await (await fetch(DJ_URL + '/nodes/' + name + '/')).json();
8
+ return data;
9
+ },
10
+
11
+ upstreams: async function (name) {
12
+ const data = await (
13
+ await fetch(DJ_URL + '/nodes/' + name + '/upstream/')
14
+ ).json();
15
+ return data;
16
+ },
17
+
18
+ downstreams: async function (name) {
19
+ const data = await (
20
+ await fetch(DJ_URL + '/nodes/' + name + '/downstream/')
21
+ ).json();
22
+ return data;
23
+ },
24
+
25
+ metric: async function (name) {
26
+ const data = await (await fetch(DJ_URL + '/metrics/' + name + '/')).json();
27
+ return data;
28
+ },
29
+
30
+ namespace: async function (nmspce) {
31
+ const data = await (
32
+ await fetch(DJ_URL + '/namespaces/' + nmspce + '/')
33
+ ).json();
34
+ return data;
35
+ },
36
+
37
+ namespaces: async function () {
38
+ const data = await (await fetch(DJ_URL + '/namespaces/')).json();
39
+ return data;
40
+ },
41
+
42
+ lineage: async function (node) {},
43
+
44
+ dag: async function (namespace = 'default') {
45
+ const edges = [];
46
+ const data = await (await fetch(DJ_URL + '/nodes/')).json();
47
+
48
+ // const metrics = await (await fetch(DJ_URL + '/metrics/')).json();
49
+
50
+ data.forEach(obj => {
51
+ obj.parents.forEach(parent => {
52
+ if (parent.name) {
53
+ edges.push({
54
+ id: obj.name + '-' + parent.name,
55
+ target: obj.name,
56
+ source: parent.name,
57
+ animated: true,
58
+ markerEnd: {
59
+ type: MarkerType.Arrow,
60
+ },
61
+ });
62
+ }
63
+ });
64
+
65
+ obj.columns.forEach(col => {
66
+ if (col.dimension) {
67
+ edges.push({
68
+ id: obj.name + '-' + col.dimension.name,
69
+ target: obj.name,
70
+ source: col.dimension.name,
71
+ draggable: true,
72
+ });
73
+ }
74
+ });
75
+ });
76
+ const namespaces = new Set(
77
+ data.flatMap(node => node.name.split('.').slice(0, -1)),
78
+ );
79
+ const namespaceNodes = Array.from(namespaces).map(namespace => {
80
+ return {
81
+ id: String(namespace),
82
+ type: 'DJNamespace',
83
+ data: {
84
+ label: String(namespace),
85
+ },
86
+ };
87
+ });
88
+
89
+ const nodes = data.map((node, index) => {
90
+ const primary_key = node.columns
91
+ .filter(col =>
92
+ col.attributes.some(
93
+ attr => attr.attribute_type.name === 'primary_key',
94
+ ),
95
+ )
96
+ .map(col => col.name);
97
+ const column_names = node.columns.map(col => {
98
+ return { name: col.name, type: col.type };
99
+ });
100
+ // const dimensions = node.type === "metric" ? metrics.filter(metric => metric.name === node.name)[0].dimensions : [];
101
+ return {
102
+ id: String(node.name),
103
+ type: 'DJNode',
104
+ data: {
105
+ label:
106
+ node.table !== null
107
+ ? String(node.schema_ + '.' + node.table)
108
+ : String(node.name),
109
+ table: node.table,
110
+ name: String(node.name),
111
+ display_name: String(node.display_name),
112
+ type: node.type,
113
+ primary_key: primary_key,
114
+ column_names: column_names,
115
+ // dimensions: dimensions,
116
+ },
117
+ // parentNode: [node.name.split(".").slice(-2, -1)],
118
+ // extent: 'parent',
119
+ };
120
+ });
121
+
122
+ return { edges: edges, nodes: nodes, namespaces: namespaceNodes };
123
+ },
124
+ };
package/src/index.tsx ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * index.tsx
3
+ *
4
+ * This is the entry file for the application, only setup and boilerplate
5
+ * code.
6
+ */
7
+
8
+ import 'react-app-polyfill/ie11';
9
+ import 'react-app-polyfill/stable';
10
+
11
+ import * as React from 'react';
12
+ import ReactDOM from 'react-dom/client';
13
+ import FontFaceObserver from 'fontfaceobserver';
14
+
15
+ // Use consistent styling
16
+ import 'sanitize.css/sanitize.css';
17
+
18
+ import { App } from 'app';
19
+
20
+ import { HelmetProvider } from 'react-helmet-async';
21
+ import reportWebVitals from 'reportWebVitals';
22
+
23
+ // Observe loading of Inter (to remove 'Inter', remove the <link> tag in
24
+ // the index.html file and this observer)
25
+ const openSansObserver = new FontFaceObserver('Inter', {});
26
+
27
+ // When Inter is loaded, add a font-family using Inter to the body
28
+ openSansObserver.load().then(() => {
29
+ document.body.classList.add('fontLoaded');
30
+ });
31
+
32
+ const root = ReactDOM.createRoot(
33
+ document.getElementById('root') as HTMLElement,
34
+ );
35
+
36
+ root.render(
37
+ <HelmetProvider>
38
+ <React.StrictMode>
39
+ <App />
40
+ </React.StrictMode>
41
+ </HelmetProvider>,
42
+ );
43
+
44
+ // If you want to start measuring performance in your app, pass a function
45
+ // to log results (for example: reportWebVitals(console.log))
46
+ // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
47
+ reportWebVitals();
@@ -0,0 +1,4 @@
1
+ /// <reference types="react-scripts" />
2
+
3
+ // To solve the issue: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31245
4
+ /// <reference types="styled-components/cssprop" />
@@ -0,0 +1,15 @@
1
+ import { ReportHandler } from 'web-vitals';
2
+
3
+ const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4
+ if (onPerfEntry && onPerfEntry instanceof Function) {
5
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6
+ getCLS(onPerfEntry);
7
+ getFID(onPerfEntry);
8
+ getFCP(onPerfEntry);
9
+ getLCP(onPerfEntry);
10
+ getTTFB(onPerfEntry);
11
+ });
12
+ }
13
+ };
14
+
15
+ export default reportWebVitals;
@@ -0,0 +1,8 @@
1
+ // react-testing-library renders your components to document.body,
2
+ // this adds jest-dom's custom assertions
3
+ import '@testing-library/jest-dom/extend-expect';
4
+
5
+ import 'react-app-polyfill/ie11';
6
+ import 'react-app-polyfill/stable';
7
+
8
+ import 'jest-styled-components';
@@ -0,0 +1,117 @@
1
+ import { createGlobalStyle } from 'styled-components';
2
+ // import { StyleConstants } from './StyleConstants';
3
+ /* istanbul ignore next */
4
+ export const DAGStyle = createGlobalStyle`
5
+ .react-flow__node-custom {
6
+ font-size: 1.2em;
7
+ width: 180px;
8
+ background: #f5f5f6;
9
+ color: #222;
10
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 15%), 0 2px 4px -1px rgb(0 0 0 / 8%);
11
+ border-radius: 2px;
12
+ }
13
+ .react-flow {
14
+ width: 100%; height: 800px; overflow: hidden; position: relative; z-index: 0;
15
+ }
16
+ .react-flow__node-custom .react-flow__handle {
17
+ top: 24px;
18
+ right: -15px;
19
+ width: 6px;
20
+ height: 10px;
21
+ border-radius: 2px;
22
+ background-color: #778899;
23
+ }
24
+
25
+ .react-flow__node.circle {
26
+ border-radius: 50%;
27
+ width: 60px;
28
+ height: 60px;
29
+ display: flex;
30
+ justify-content: center;
31
+ align-items: center;
32
+ font-weight: 700;
33
+ }
34
+
35
+ .react-flow__node.annotation {
36
+ border-radius: 0;
37
+ text-align: left;
38
+ background: white;
39
+ border: none;
40
+ line-height: 1.4;
41
+ width: 225px;
42
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 15%), 0 2px 4px -1px rgb(0 0 0 / 8%);
43
+ }
44
+
45
+ .react-flow__node.annotation .react-flow__handle {
46
+ display: none;
47
+ }
48
+
49
+ .dj-node__header {
50
+ font-weight: 400;
51
+ text-transform: uppercase;
52
+ font-family: 'jetbrains-mono',monospace;
53
+ font-size: 1.5em;
54
+ padding-inline-start: 0.5rem;
55
+ padding-inline-end: 0.5rem;
56
+ padding-left: 0.75em;
57
+ padding-top: 0.35rem;
58
+ padding-bottom: 0.35rem;
59
+ border-bottom-width: 1px;
60
+ border-bottom-style: solid;
61
+ border-color: #c4cbd1;
62
+ }
63
+
64
+ .dj-node__body {
65
+ background-color: rgb(254, 254, 254);
66
+ padding: 0.5em 0.7em 0.9em 0.7em;
67
+ font-family: 'nt-dapper',-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
68
+ font-size: 1.7em;
69
+ }
70
+
71
+ .dj-node__full {
72
+ display: flex;
73
+ flex-direction: column;
74
+ height: 100%;
75
+ border-width: 1px;
76
+ border-style: solid;
77
+ border-image: initial;
78
+ border-color: #b0b9c2;
79
+ border-radius: 8px;
80
+ overflow: hidden;
81
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
82
+ }
83
+
84
+ .dj-node__metadata {
85
+ padding: 1em;
86
+ font-family: 'nt-dapper',-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
87
+ font-size: 1em;
88
+ }
89
+
90
+ .collapse-button {
91
+ display: block;
92
+ width: 100%;
93
+ font: 0.8em "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif;
94
+ text-transform: uppercase;
95
+ border: none;
96
+ margin-top: 0.2em;
97
+ padding: 0.35em;
98
+ }
99
+ .collapse {
100
+ padding-top: 10px;
101
+ }
102
+ .collapse-content.collapsed {
103
+ display: none;
104
+ }
105
+ .collapsed-content.expanded {
106
+ display: block;
107
+ }
108
+ .collapse tr td {
109
+ padding-left: 5px;
110
+ padding-bottom: 5px;
111
+ }
112
+ .serif {
113
+ font-family: 'jetbrains-mono', monospace;
114
+ text-transform: lowercase;
115
+ }
116
+
117
+ `;