datajunction-ui 0.0.1-rc.1 → 0.0.1-rc.11
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.
- package/.github/workflows/ci.yml +3 -3
- package/.prettierignore +3 -1
- package/package.json +16 -8
- package/src/app/__tests__/__snapshots__/index.test.tsx.snap +67 -25
- package/src/app/components/NamespaceHeader.jsx +4 -13
- package/src/app/components/QueryInfo.jsx +109 -0
- package/src/app/components/Tab.jsx +1 -8
- package/src/app/components/ToggleSwitch.jsx +17 -0
- package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +2 -18
- package/src/app/components/djgraph/Collapse.jsx +46 -0
- package/src/app/components/djgraph/DJNode.jsx +56 -80
- package/src/app/components/djgraph/DJNodeColumns.jsx +68 -0
- package/src/app/components/djgraph/DJNodeDimensions.jsx +69 -0
- package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +82 -43
- package/src/app/icons/CollapsedIcon.jsx +15 -0
- package/src/app/icons/ExpandedIcon.jsx +15 -0
- package/src/app/icons/HorizontalHierarchyIcon.jsx +15 -0
- package/src/app/icons/InvalidIcon.jsx +14 -0
- package/src/app/icons/PythonIcon.jsx +52 -0
- package/src/app/icons/TableIcon.jsx +14 -0
- package/src/app/icons/ValidIcon.jsx +14 -0
- package/src/app/index.tsx +28 -15
- package/src/app/pages/NamespacePage/Explorer.jsx +57 -0
- package/src/app/pages/NamespacePage/Loadable.jsx +9 -7
- package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +39 -17
- package/src/app/pages/NamespacePage/index.jsx +90 -28
- package/src/app/pages/NodePage/ClientCodePopover.jsx +30 -0
- package/src/app/pages/NodePage/Loadable.jsx +9 -7
- package/src/app/pages/NodePage/NodeColumnTab.jsx +36 -20
- package/src/app/pages/NodePage/NodeGraphTab.jsx +83 -54
- package/src/app/pages/NodePage/NodeHistory.jsx +71 -0
- package/src/app/pages/NodePage/NodeInfoTab.jsx +132 -49
- package/src/app/pages/NodePage/NodeMaterializationTab.jsx +151 -0
- package/src/app/pages/NodePage/NodeSQLTab.jsx +100 -0
- package/src/app/pages/NodePage/NodeStatus.jsx +14 -20
- package/src/app/pages/NodePage/index.jsx +49 -13
- package/src/app/pages/Root/index.tsx +5 -0
- package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
- package/src/app/pages/SQLBuilderPage/index.jsx +344 -0
- package/src/app/providers/djclient.jsx +5 -0
- package/src/app/services/DJService.js +125 -1
- package/src/styles/dag.css +111 -5
- package/src/styles/index.css +343 -25
- package/tsconfig.json +1 -1
- package/webpack.config.js +22 -6
- package/.babelrc +0 -4
- package/.env.local +0 -4
- package/.env.production +0 -1
- package/.vscode/extensions.json +0 -7
- package/.vscode/launch.json +0 -15
- package/.vscode/settings.json +0 -25
- package/Dockerfile +0 -7
- package/dist/5fa71a03d45dc2e3d61447f3013a303d.png +0 -0
- package/dist/index.html +0 -26
- package/dist/main.js +0 -23303
- package/dist/vendor.js +0 -281
- package/src/app/pages/ListNamespacesPage/Loadable.jsx +0 -14
- package/src/app/pages/ListNamespacesPage/index.jsx +0 -52
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Handle } from 'reactflow';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
export function DJNodeColumns({ data, limit }) {
|
|
5
|
+
const handleWrapperStyle = {
|
|
6
|
+
display: 'flex',
|
|
7
|
+
position: 'absolute',
|
|
8
|
+
height: '100%',
|
|
9
|
+
flexDirection: 'column',
|
|
10
|
+
top: '50%',
|
|
11
|
+
justifyContent: 'space-between',
|
|
12
|
+
};
|
|
13
|
+
const handleWrapperStyleRight = { ...handleWrapperStyle, ...{ right: 0 } };
|
|
14
|
+
|
|
15
|
+
const handleStyle = {
|
|
16
|
+
width: '12px',
|
|
17
|
+
height: '12px',
|
|
18
|
+
borderRadius: '12px',
|
|
19
|
+
background: 'transparent',
|
|
20
|
+
border: '4px solid transparent',
|
|
21
|
+
cursor: 'pointer',
|
|
22
|
+
position: 'absolute',
|
|
23
|
+
top: '0px',
|
|
24
|
+
left: 0,
|
|
25
|
+
};
|
|
26
|
+
const handleStyleLeft = percentage => {
|
|
27
|
+
return {
|
|
28
|
+
...handleStyle,
|
|
29
|
+
...{
|
|
30
|
+
transform: 'translate(-' + percentage + '%, -50%)',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
return data.column_names.slice(0, limit).map(col => (
|
|
35
|
+
<div className={'custom-node-subheader node_type__' + data.type}>
|
|
36
|
+
<div style={handleWrapperStyle}>
|
|
37
|
+
<Handle
|
|
38
|
+
type="target"
|
|
39
|
+
position="left"
|
|
40
|
+
id={data.name + '.' + col.name}
|
|
41
|
+
style={handleStyleLeft(100)}
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
<div
|
|
45
|
+
className="custom-node-port"
|
|
46
|
+
id={data.name + '.' + col.name}
|
|
47
|
+
key={'i-' + data.name + '.' + col.name}
|
|
48
|
+
>
|
|
49
|
+
{data.primary_key.includes(col.name) ? (
|
|
50
|
+
<b>{col.name} (PK)</b>
|
|
51
|
+
) : (
|
|
52
|
+
<>{col.name}</>
|
|
53
|
+
)}
|
|
54
|
+
<span style={{ marginLeft: '0.25rem' }} className={'badge'}>
|
|
55
|
+
{col.type}
|
|
56
|
+
</span>
|
|
57
|
+
</div>
|
|
58
|
+
<div style={handleWrapperStyleRight}>
|
|
59
|
+
<Handle
|
|
60
|
+
type="source"
|
|
61
|
+
position="right"
|
|
62
|
+
id={data.name + '.' + col.name}
|
|
63
|
+
style={handleStyle}
|
|
64
|
+
/>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
));
|
|
68
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React, { useContext, useEffect, useState } from 'react';
|
|
2
|
+
import DJClientContext from '../../providers/djclient';
|
|
3
|
+
import Collapse from './Collapse';
|
|
4
|
+
|
|
5
|
+
export function DJNodeDimensions(data) {
|
|
6
|
+
const [dimensions, setDimensions] = useState([]);
|
|
7
|
+
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (data.type === 'metric') {
|
|
10
|
+
async function getDimensions() {
|
|
11
|
+
try {
|
|
12
|
+
const metricData = await djClient.metric(data.name);
|
|
13
|
+
setDimensions(metricData.dimensions);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.log(err);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
getDimensions();
|
|
19
|
+
}
|
|
20
|
+
}, [data, djClient]);
|
|
21
|
+
const dimensionsToObject = dimensions => {
|
|
22
|
+
return dimensions.map(dim => {
|
|
23
|
+
const [attribute, ...nodeName] = dim.name.split('.').reverse();
|
|
24
|
+
return {
|
|
25
|
+
dimension: nodeName.reverse().join('.'),
|
|
26
|
+
path: dim.path,
|
|
27
|
+
column: attribute,
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const groupedDimensions = dims =>
|
|
32
|
+
dims.reduce((acc, current) => {
|
|
33
|
+
const dimKey = current.dimension + ' via ' + current.path.slice(-1);
|
|
34
|
+
acc[dimKey] = acc[dimKey] || {
|
|
35
|
+
dimension: current.dimension,
|
|
36
|
+
path: current.path.slice(-1),
|
|
37
|
+
columns: [],
|
|
38
|
+
};
|
|
39
|
+
acc[dimKey].columns.push(current.column);
|
|
40
|
+
return acc;
|
|
41
|
+
}, {});
|
|
42
|
+
const dimensionsRenderer = grouped =>
|
|
43
|
+
Object.entries(grouped).map(([dimKey, dimValue]) => {
|
|
44
|
+
if (Array.isArray(dimValue.columns)) {
|
|
45
|
+
const attributes = dimValue.columns.map(col => {
|
|
46
|
+
return <span className={'badge white_badge'}>{col}</span>;
|
|
47
|
+
});
|
|
48
|
+
return (
|
|
49
|
+
<div className={'custom-node-subheader node_type__' + data.type}>
|
|
50
|
+
<div className="custom-node-port">
|
|
51
|
+
<a href={`/nodes/${dimValue.dimension}`}>{dimValue.dimension}</a>{' '}
|
|
52
|
+
<div className={'badge node_type__metric text-black'}>
|
|
53
|
+
{dimValue.path}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div className={'dimension_attributes'}>{attributes}</div>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return <></>;
|
|
61
|
+
});
|
|
62
|
+
return (
|
|
63
|
+
<>
|
|
64
|
+
{dimensions.length <= 0
|
|
65
|
+
? ''
|
|
66
|
+
: dimensionsRenderer(groupedDimensions(dimensionsToObject(dimensions)))}
|
|
67
|
+
</>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
@@ -2,24 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`<DJNode /> should render and match the snapshot 1`] = `
|
|
4
4
|
<React.Fragment>
|
|
5
|
-
<Memo(Handle)
|
|
6
|
-
position="left"
|
|
7
|
-
style={
|
|
8
|
-
Object {
|
|
9
|
-
"backgroundColor": "#ccc",
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
type="target"
|
|
13
|
-
/>
|
|
14
5
|
<div
|
|
15
|
-
className="dj-node__full"
|
|
16
|
-
style={
|
|
17
|
-
Object {
|
|
18
|
-
"backgroundColor": "#7EB46150",
|
|
19
|
-
"color": "#7EB461",
|
|
20
|
-
}
|
|
21
|
-
}
|
|
6
|
+
className="dj-node__full node_type__source"
|
|
22
7
|
>
|
|
8
|
+
<div
|
|
9
|
+
style={
|
|
10
|
+
Object {
|
|
11
|
+
"display": "flex",
|
|
12
|
+
"flexDirection": "column",
|
|
13
|
+
"height": "100%",
|
|
14
|
+
"justifyContent": "space-between",
|
|
15
|
+
"position": "absolute",
|
|
16
|
+
"top": "50%",
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
>
|
|
20
|
+
<Memo(Handle)
|
|
21
|
+
id="shared.dimensions.accounts"
|
|
22
|
+
position="left"
|
|
23
|
+
style={
|
|
24
|
+
Object {
|
|
25
|
+
"background": "transparent",
|
|
26
|
+
"border": "4px solid transparent",
|
|
27
|
+
"borderRadius": "12px",
|
|
28
|
+
"cursor": "pointer",
|
|
29
|
+
"height": "12px",
|
|
30
|
+
"left": 0,
|
|
31
|
+
"position": "absolute",
|
|
32
|
+
"top": "0px",
|
|
33
|
+
"transform": "translate(-100%, -50%)",
|
|
34
|
+
"width": "12px",
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
type="target"
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
23
40
|
<div
|
|
24
41
|
className="dj-node__header"
|
|
25
42
|
>
|
|
@@ -37,37 +54,59 @@ exports[`<DJNode /> should render and match the snapshot 1`] = `
|
|
|
37
54
|
</b>
|
|
38
55
|
:
|
|
39
56
|
|
|
57
|
+
<a
|
|
58
|
+
href="/nodes/shared.dimensions.accounts"
|
|
59
|
+
/>
|
|
40
60
|
<Collapse
|
|
41
61
|
collapsed={true}
|
|
62
|
+
data={
|
|
63
|
+
Object {
|
|
64
|
+
"column_names": Array [
|
|
65
|
+
"a",
|
|
66
|
+
],
|
|
67
|
+
"name": "shared.dimensions.accounts",
|
|
68
|
+
"primary_key": Array [
|
|
69
|
+
"id",
|
|
70
|
+
],
|
|
71
|
+
"type": "source",
|
|
72
|
+
}
|
|
73
|
+
}
|
|
42
74
|
text="columns"
|
|
43
|
-
|
|
44
|
-
<div
|
|
45
|
-
className="dj-node__metadata"
|
|
46
|
-
>
|
|
47
|
-
<tr>
|
|
48
|
-
<td>
|
|
49
|
-
<React.Fragment />
|
|
50
|
-
</td>
|
|
51
|
-
<td
|
|
52
|
-
style={
|
|
53
|
-
Object {
|
|
54
|
-
"textAlign": "right",
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/>
|
|
58
|
-
</tr>
|
|
59
|
-
</div>
|
|
60
|
-
</Collapse>
|
|
75
|
+
/>
|
|
61
76
|
</div>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
<div
|
|
78
|
+
style={
|
|
79
|
+
Object {
|
|
80
|
+
"display": "flex",
|
|
81
|
+
"flexDirection": "column",
|
|
82
|
+
"height": "100%",
|
|
83
|
+
"justifyContent": "space-between",
|
|
84
|
+
"position": "absolute",
|
|
85
|
+
"right": 0,
|
|
86
|
+
"top": "50%",
|
|
87
|
+
}
|
|
68
88
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
>
|
|
90
|
+
<Memo(Handle)
|
|
91
|
+
id="shared.dimensions.accounts"
|
|
92
|
+
position="right"
|
|
93
|
+
style={
|
|
94
|
+
Object {
|
|
95
|
+
"background": "transparent",
|
|
96
|
+
"border": "4px solid transparent",
|
|
97
|
+
"borderRadius": "12px",
|
|
98
|
+
"cursor": "pointer",
|
|
99
|
+
"height": "12px",
|
|
100
|
+
"left": 0,
|
|
101
|
+
"position": "absolute",
|
|
102
|
+
"top": "0px",
|
|
103
|
+
"transform": "translate(-90%, -50%)",
|
|
104
|
+
"width": "12px",
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
type="source"
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
72
111
|
</React.Fragment>
|
|
73
112
|
`;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const CollapsedIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
stroke="currentColor"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
strokeWidth="0"
|
|
6
|
+
viewBox="0 0 512 512"
|
|
7
|
+
height="1em"
|
|
8
|
+
width="1em"
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
+
>
|
|
11
|
+
<path d="M48 256c0 114.9 93.1 208 208 208s208-93.1 208-208S370.9 48 256 48 48 141.1 48 256zm244.5 0l-81.9-81.1c-7.5-7.5-7.5-19.8 0-27.3s19.8-7.5 27.3 0l95.4 95.7c7.3 7.3 7.5 19.1.6 26.6l-94 94.3c-3.8 3.8-8.7 5.7-13.7 5.7-4.9 0-9.9-1.9-13.6-5.6-7.5-7.5-7.6-19.7 0-27.3l79.9-81z"></path>
|
|
12
|
+
</svg>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export default CollapsedIcon;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const ExpandedIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
stroke="currentColor"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
strokeWidth="0"
|
|
6
|
+
viewBox="0 0 512 512"
|
|
7
|
+
height="1em"
|
|
8
|
+
width="1em"
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
+
>
|
|
11
|
+
<path d="M48 256c0 114.9 93.1 208 208 208s208-93.1 208-208S370.9 48 256 48 48 141.1 48 256zm289.1-43.4c7.5-7.5 19.8-7.5 27.3 0 3.8 3.8 5.6 8.7 5.6 13.6s-1.9 9.9-5.7 13.7l-94.3 94c-7.6 6.9-19.3 6.7-26.6-.6l-95.7-95.4c-7.5-7.5-7.6-19.7 0-27.3 7.5-7.5 19.7-7.6 27.3 0l81.1 81.9 81-79.9z"></path>
|
|
12
|
+
</svg>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export default ExpandedIcon;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const HorizontalHierarchyIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="16"
|
|
5
|
+
height="16"
|
|
6
|
+
fill="currentColor"
|
|
7
|
+
className="bi bi-house-door-fill"
|
|
8
|
+
viewBox="0 0 16 16"
|
|
9
|
+
style={{ paddingBottom: '0.2rem' }}
|
|
10
|
+
>
|
|
11
|
+
<path d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z" />
|
|
12
|
+
</svg>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export default HorizontalHierarchyIcon;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const InvalidIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="25"
|
|
5
|
+
height="25"
|
|
6
|
+
fill="currentColor"
|
|
7
|
+
className="bi bi-x-circle-fill"
|
|
8
|
+
viewBox="0 0 16 16"
|
|
9
|
+
>
|
|
10
|
+
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z" />
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export default InvalidIcon;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const PythonIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
width="45px"
|
|
4
|
+
height="45px"
|
|
5
|
+
viewBox="0 0 64 64"
|
|
6
|
+
fill="none"
|
|
7
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8
|
+
>
|
|
9
|
+
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
|
|
10
|
+
<g
|
|
11
|
+
id="SVGRepo_tracerCarrier"
|
|
12
|
+
strokeLinecap="round"
|
|
13
|
+
strokeLinejoin="round"
|
|
14
|
+
></g>
|
|
15
|
+
<g id="SVGRepo_iconCarrier">
|
|
16
|
+
<path
|
|
17
|
+
d="M31.885 16c-8.124 0-7.617 3.523-7.617 3.523l.01 3.65h7.752v1.095H21.197S16 23.678 16 31.876c0 8.196 4.537 7.906 4.537 7.906h2.708v-3.804s-.146-4.537 4.465-4.537h7.688s4.32.07 4.32-4.175v-7.019S40.374 16 31.885 16zm-4.275 2.454c.771 0 1.395.624 1.395 1.395s-.624 1.395-1.395 1.395a1.393 1.393 0 0 1-1.395-1.395c0-.771.624-1.395 1.395-1.395z"
|
|
18
|
+
fill="url(#a)"
|
|
19
|
+
></path>
|
|
20
|
+
<path
|
|
21
|
+
d="M32.115 47.833c8.124 0 7.617-3.523 7.617-3.523l-.01-3.65H31.97v-1.095h10.832S48 40.155 48 31.958c0-8.197-4.537-7.906-4.537-7.906h-2.708v3.803s.146 4.537-4.465 4.537h-7.688s-4.32-.07-4.32 4.175v7.019s-.656 4.247 7.833 4.247zm4.275-2.454a1.393 1.393 0 0 1-1.395-1.395c0-.77.624-1.394 1.395-1.394s1.395.623 1.395 1.394c0 .772-.624 1.395-1.395 1.395z"
|
|
22
|
+
fill="url(#b)"
|
|
23
|
+
></path>
|
|
24
|
+
<defs>
|
|
25
|
+
<linearGradient
|
|
26
|
+
id="a"
|
|
27
|
+
x1="19.075"
|
|
28
|
+
y1="18.782"
|
|
29
|
+
x2="34.898"
|
|
30
|
+
y2="34.658"
|
|
31
|
+
gradientUnits="userSpaceOnUse"
|
|
32
|
+
>
|
|
33
|
+
<stop stopColor="#387EB8"></stop>
|
|
34
|
+
<stop offset="1" stopColor="#366994"></stop>
|
|
35
|
+
</linearGradient>
|
|
36
|
+
<linearGradient
|
|
37
|
+
id="b"
|
|
38
|
+
x1="28.809"
|
|
39
|
+
y1="28.882"
|
|
40
|
+
x2="45.803"
|
|
41
|
+
y2="45.163"
|
|
42
|
+
gradientUnits="userSpaceOnUse"
|
|
43
|
+
>
|
|
44
|
+
<stop stopColor="#FFE052"></stop>
|
|
45
|
+
<stop offset="1" stopColor="#FFC331"></stop>
|
|
46
|
+
</linearGradient>
|
|
47
|
+
</defs>
|
|
48
|
+
</g>
|
|
49
|
+
</svg>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
export default PythonIcon;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const TableIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="16"
|
|
5
|
+
height="16"
|
|
6
|
+
fill="currentColor"
|
|
7
|
+
className="bi bi-table"
|
|
8
|
+
viewBox="0 0 16 16"
|
|
9
|
+
>
|
|
10
|
+
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm15 2h-4v3h4V4zm0 4h-4v3h4V8zm0 4h-4v3h3a1 1 0 0 0 1-1v-2zm-5 3v-3H6v3h4zm-5 0v-3H1v2a1 1 0 0 0 1 1h3zm-4-4h4V8H1v3zm0-4h4V4H1v3zm5-3v3h4V4H6zm4 4H6v3h4V8z" />
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export default TableIcon;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const ValidIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="25"
|
|
5
|
+
height="25"
|
|
6
|
+
fill="currentColor"
|
|
7
|
+
className="bi bi-check-circle-fill"
|
|
8
|
+
viewBox="0 0 16 16"
|
|
9
|
+
>
|
|
10
|
+
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z" />
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export default ValidIcon;
|
package/src/app/index.tsx
CHANGED
|
@@ -9,9 +9,11 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
|
9
9
|
|
|
10
10
|
import { NamespacePage } from './pages/NamespacePage/Loadable';
|
|
11
11
|
import { NodePage } from './pages/NodePage/Loadable';
|
|
12
|
+
import { SQLBuilderPage } from './pages/SQLBuilderPage/Loadable';
|
|
12
13
|
import { NotFoundPage } from './pages/NotFoundPage/Loadable';
|
|
13
14
|
import { Root } from './pages/Root/Loadable';
|
|
14
|
-
import
|
|
15
|
+
import DJClientContext from './providers/djclient';
|
|
16
|
+
import { DataJunctionAPI } from './services/DJService';
|
|
15
17
|
|
|
16
18
|
export function App() {
|
|
17
19
|
return (
|
|
@@ -25,21 +27,32 @@ export function App() {
|
|
|
25
27
|
content="DataJunction serves as a semantic layer to help manage metrics"
|
|
26
28
|
/>
|
|
27
29
|
</Helmet>
|
|
30
|
+
<DJClientContext.Provider value={{ DataJunctionAPI }}>
|
|
31
|
+
<Routes>
|
|
32
|
+
<Route
|
|
33
|
+
path="/"
|
|
34
|
+
element={<Root />}
|
|
35
|
+
children={
|
|
36
|
+
<>
|
|
37
|
+
<Route path="nodes" key="nodes">
|
|
38
|
+
<Route path=":name" element={<NodePage />} />
|
|
39
|
+
</Route>
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
<Route path="/" element={<NamespacePage />} key="index" />
|
|
42
|
+
<Route path="namespaces">
|
|
43
|
+
<Route
|
|
44
|
+
path=":namespace"
|
|
45
|
+
element={<NamespacePage />}
|
|
46
|
+
key="namespaces"
|
|
47
|
+
/>
|
|
48
|
+
</Route>
|
|
49
|
+
<Route path="sql" key="sql" element={<SQLBuilderPage />} />
|
|
50
|
+
</>
|
|
51
|
+
}
|
|
52
|
+
/>
|
|
53
|
+
<Route path="*" element={<NotFoundPage />} />
|
|
54
|
+
</Routes>
|
|
55
|
+
</DJClientContext.Provider>
|
|
43
56
|
</BrowserRouter>
|
|
44
57
|
);
|
|
45
58
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import CollapsedIcon from '../../icons/CollapsedIcon';
|
|
3
|
+
import ExpandedIcon from '../../icons/ExpandedIcon';
|
|
4
|
+
|
|
5
|
+
const Explorer = ({ item = [], current }) => {
|
|
6
|
+
const [items, setItems] = useState([]);
|
|
7
|
+
const [expand, setExpand] = useState(false);
|
|
8
|
+
const [highlight, setHighlight] = useState(false);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setItems(item);
|
|
12
|
+
setHighlight(current);
|
|
13
|
+
if (current === undefined || current?.startsWith(item.path)) {
|
|
14
|
+
setExpand(true);
|
|
15
|
+
} else setExpand(false);
|
|
16
|
+
}, [current, item]);
|
|
17
|
+
|
|
18
|
+
const handleClickOnParent = e => {
|
|
19
|
+
e.stopPropagation();
|
|
20
|
+
setExpand(prev => {
|
|
21
|
+
return !prev;
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<>
|
|
27
|
+
<div
|
|
28
|
+
className={`select-name ${
|
|
29
|
+
highlight === items.path ? 'select-name-highlight' : ''
|
|
30
|
+
}`}
|
|
31
|
+
onClick={handleClickOnParent}
|
|
32
|
+
>
|
|
33
|
+
{items.children && items.children.length > 0 ? (
|
|
34
|
+
<span>{!expand ? <CollapsedIcon /> : <ExpandedIcon />} </span>
|
|
35
|
+
) : null}
|
|
36
|
+
<a href={`/namespaces/${items.path}`}>{items.namespace}</a>{' '}
|
|
37
|
+
</div>
|
|
38
|
+
{items.children
|
|
39
|
+
? items.children.map((item, index) => (
|
|
40
|
+
<div
|
|
41
|
+
style={{
|
|
42
|
+
paddingLeft: '1.4rem',
|
|
43
|
+
marginLeft: '1rem',
|
|
44
|
+
borderLeft: '1px solid rgb(218 233 255)',
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
<div className={`${expand ? '' : 'inactive'}`}>
|
|
48
|
+
<Explorer item={item} current={highlight} />
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
))
|
|
52
|
+
: null}
|
|
53
|
+
</>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default Explorer;
|
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import { lazyLoad } from '../../../utils/loadable';
|
|
7
7
|
|
|
8
|
-
export const NamespacePage =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
+
};
|
|
@@ -4,7 +4,6 @@ exports[`<NamespacePage /> should render and match the snapshot 1`] = `
|
|
|
4
4
|
<div
|
|
5
5
|
className="mid"
|
|
6
6
|
>
|
|
7
|
-
<NamespaceHeader />
|
|
8
7
|
<div
|
|
9
8
|
className="card"
|
|
10
9
|
>
|
|
@@ -12,31 +11,54 @@ exports[`<NamespacePage /> should render and match the snapshot 1`] = `
|
|
|
12
11
|
className="card-header"
|
|
13
12
|
>
|
|
14
13
|
<h2>
|
|
15
|
-
|
|
14
|
+
Explore
|
|
16
15
|
</h2>
|
|
17
16
|
<div
|
|
18
17
|
className="table-responsive"
|
|
19
18
|
>
|
|
19
|
+
<div
|
|
20
|
+
className="sidebar"
|
|
21
|
+
>
|
|
22
|
+
<span
|
|
23
|
+
style={
|
|
24
|
+
Object {
|
|
25
|
+
"color": "#95aac9",
|
|
26
|
+
"fontSize": "0.8125rem",
|
|
27
|
+
"fontWeight": "600",
|
|
28
|
+
"padding": "1rem 1rem 1rem 0",
|
|
29
|
+
"textTransform": "uppercase",
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
>
|
|
33
|
+
Namespaces
|
|
34
|
+
</span>
|
|
35
|
+
</div>
|
|
20
36
|
<table
|
|
21
37
|
className="card-table table"
|
|
22
38
|
>
|
|
23
39
|
<thead>
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
<tr>
|
|
41
|
+
<th>
|
|
42
|
+
Name
|
|
43
|
+
</th>
|
|
44
|
+
<th>
|
|
45
|
+
Type
|
|
46
|
+
</th>
|
|
47
|
+
<th>
|
|
48
|
+
Status
|
|
49
|
+
</th>
|
|
50
|
+
<th>
|
|
51
|
+
Mode
|
|
52
|
+
</th>
|
|
53
|
+
<th>
|
|
54
|
+
Tags
|
|
55
|
+
</th>
|
|
56
|
+
<th>
|
|
57
|
+
Last Updated
|
|
58
|
+
</th>
|
|
59
|
+
</tr>
|
|
39
60
|
</thead>
|
|
61
|
+
<tbody />
|
|
40
62
|
</table>
|
|
41
63
|
</div>
|
|
42
64
|
</div>
|