datajunction-ui 0.0.1-a1
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/.babel-plugin-macrosrc.js +5 -0
- package/.env +3 -0
- package/.eslintrc.js +20 -0
- package/.gitattributes +201 -0
- package/.husky/pre-commit +6 -0
- package/.nvmrc +1 -0
- package/.prettierignore +6 -0
- package/.prettierrc +9 -0
- package/.stylelintrc +7 -0
- package/LICENSE +22 -0
- package/Makefile +3 -0
- package/README.md +10 -0
- package/dj-logo.svg +10 -0
- package/internals/testing/loadable.mock.tsx +6 -0
- package/package.json +189 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +26 -0
- package/public/manifest.json +15 -0
- package/public/robots.txt +3 -0
- package/src/__tests__/reportWebVitals.test.jsx +44 -0
- package/src/app/__tests__/__snapshots__/index.test.tsx.snap +9 -0
- package/src/app/__tests__/index.test.tsx +14 -0
- package/src/app/components/DeleteNode.jsx +55 -0
- package/src/app/components/ListGroupItem.jsx +24 -0
- package/src/app/components/NamespaceHeader.jsx +31 -0
- package/src/app/components/QueryInfo.jsx +77 -0
- package/src/app/components/Tab.jsx +25 -0
- package/src/app/components/ToggleSwitch.jsx +20 -0
- package/src/app/components/__tests__/DeleteNode.test.jsx +53 -0
- package/src/app/components/__tests__/ListGroupItem.test.tsx +16 -0
- package/src/app/components/__tests__/NamespaceHeader.test.jsx +14 -0
- package/src/app/components/__tests__/QueryInfo.test.jsx +55 -0
- package/src/app/components/__tests__/Tab.test.jsx +27 -0
- package/src/app/components/__tests__/ToggleSwitch.test.jsx +43 -0
- package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +29 -0
- package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +47 -0
- package/src/app/components/djgraph/Collapse.jsx +46 -0
- package/src/app/components/djgraph/DJNode.jsx +89 -0
- package/src/app/components/djgraph/DJNodeColumns.jsx +71 -0
- package/src/app/components/djgraph/DJNodeDimensions.jsx +75 -0
- package/src/app/components/djgraph/LayoutFlow.jsx +104 -0
- package/src/app/components/djgraph/__tests__/Collapse.test.jsx +51 -0
- package/src/app/components/djgraph/__tests__/DJNode.test.tsx +24 -0
- package/src/app/components/djgraph/__tests__/DJNodeColumns.test.jsx +83 -0
- package/src/app/components/djgraph/__tests__/DJNodeDimensions.test.jsx +118 -0
- package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +117 -0
- package/src/app/constants.js +2 -0
- package/src/app/icons/AlertIcon.jsx +32 -0
- package/src/app/icons/CollapsedIcon.jsx +15 -0
- package/src/app/icons/DJLogo.jsx +36 -0
- package/src/app/icons/DeleteIcon.jsx +21 -0
- package/src/app/icons/EditIcon.jsx +18 -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/LoadingIcon.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 +108 -0
- package/src/app/pages/AddEditNodePage/FormikSelect.jsx +46 -0
- package/src/app/pages/AddEditNodePage/FullNameField.jsx +37 -0
- package/src/app/pages/AddEditNodePage/Loadable.jsx +16 -0
- package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +89 -0
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +103 -0
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +132 -0
- package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +75 -0
- package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +31 -0
- package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +54 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +3 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +3 -0
- package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +180 -0
- package/src/app/pages/AddEditNodePage/index.jsx +396 -0
- package/src/app/pages/AddEditTagPage/Loadable.jsx +16 -0
- package/src/app/pages/AddEditTagPage/__tests__/AddEditTagPage.test.jsx +107 -0
- package/src/app/pages/AddEditTagPage/index.jsx +132 -0
- package/src/app/pages/LoginPage/LoginForm.jsx +124 -0
- package/src/app/pages/LoginPage/SignupForm.jsx +156 -0
- package/src/app/pages/LoginPage/__tests__/index.test.jsx +97 -0
- package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
- package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
- package/src/app/pages/LoginPage/index.jsx +17 -0
- package/src/app/pages/NamespacePage/AddNamespacePopover.jsx +85 -0
- package/src/app/pages/NamespacePage/Explorer.jsx +57 -0
- package/src/app/pages/NamespacePage/Loadable.jsx +16 -0
- package/src/app/pages/NamespacePage/__tests__/index.test.jsx +217 -0
- package/src/app/pages/NamespacePage/index.jsx +199 -0
- package/src/app/pages/NodePage/AddBackfillPopover.jsx +166 -0
- package/src/app/pages/NodePage/AddMaterializationPopover.jsx +161 -0
- package/src/app/pages/NodePage/ClientCodePopover.jsx +46 -0
- package/src/app/pages/NodePage/EditColumnPopover.jsx +116 -0
- package/src/app/pages/NodePage/LinkDimensionPopover.jsx +149 -0
- package/src/app/pages/NodePage/Loadable.jsx +16 -0
- package/src/app/pages/NodePage/NodeColumnTab.jsx +200 -0
- package/src/app/pages/NodePage/NodeGraphTab.jsx +112 -0
- package/src/app/pages/NodePage/NodeHistory.jsx +212 -0
- package/src/app/pages/NodePage/NodeInfoTab.jsx +212 -0
- package/src/app/pages/NodePage/NodeLineageTab.jsx +84 -0
- package/src/app/pages/NodePage/NodeMaterializationTab.jsx +233 -0
- package/src/app/pages/NodePage/NodeSQLTab.jsx +82 -0
- package/src/app/pages/NodePage/NodeStatus.jsx +28 -0
- package/src/app/pages/NodePage/NodesWithDimension.jsx +42 -0
- package/src/app/pages/NodePage/PartitionColumnPopover.jsx +153 -0
- package/src/app/pages/NodePage/__tests__/AddBackfillPopover.test.jsx +47 -0
- package/src/app/pages/NodePage/__tests__/ClientCodePopover.test.jsx +49 -0
- package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +148 -0
- package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +165 -0
- package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +591 -0
- package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +57 -0
- package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +757 -0
- package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
- package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +403 -0
- package/src/app/pages/NodePage/index.jsx +210 -0
- package/src/app/pages/NotFoundPage/Loadable.tsx +14 -0
- package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
- package/src/app/pages/NotFoundPage/index.tsx +23 -0
- package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
- package/src/app/pages/RegisterTablePage/__tests__/RegisterTablePage.test.jsx +110 -0
- package/src/app/pages/RegisterTablePage/__tests__/__snapshots__/RegisterTablePage.test.jsx.snap +37 -0
- package/src/app/pages/RegisterTablePage/index.jsx +142 -0
- package/src/app/pages/Root/Loadable.tsx +14 -0
- package/src/app/pages/Root/__tests__/index.test.jsx +77 -0
- package/src/app/pages/Root/assets/dj-logo.png +0 -0
- package/src/app/pages/Root/index.tsx +70 -0
- package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
- package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
- package/src/app/pages/SQLBuilderPage/index.jsx +390 -0
- package/src/app/pages/TagPage/Loadable.jsx +16 -0
- package/src/app/pages/TagPage/__tests__/TagPage.test.jsx +70 -0
- package/src/app/pages/TagPage/index.jsx +79 -0
- package/src/app/providers/djclient.jsx +5 -0
- package/src/app/services/DJService.js +665 -0
- package/src/app/services/__tests__/DJService.test.jsx +804 -0
- package/src/index.tsx +48 -0
- package/src/mocks/mockNodes.jsx +1430 -0
- package/src/react-app-env.d.ts +4 -0
- package/src/reportWebVitals.ts +15 -0
- package/src/setupTests.ts +36 -0
- package/src/styles/dag.css +228 -0
- package/src/styles/index.css +1083 -0
- package/src/styles/loading.css +34 -0
- package/src/styles/login.css +81 -0
- package/src/styles/node-creation.scss +197 -0
- package/src/styles/styles.scss +44 -0
- package/src/styles/styles.scss.d.ts +9 -0
- package/src/utils/__tests__/__snapshots__/loadable.test.tsx.snap +17 -0
- package/src/utils/__tests__/loadable.test.tsx +53 -0
- package/src/utils/__tests__/request.test.ts +82 -0
- package/src/utils/form.jsx +23 -0
- package/src/utils/loadable.tsx +30 -0
- package/src/utils/request.ts +54 -0
- package/tsconfig.json +34 -0
- package/webpack.config.js +118 -0
|
@@ -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,36 @@
|
|
|
1
|
+
const DJLogo = props => (
|
|
2
|
+
<svg
|
|
3
|
+
width="30"
|
|
4
|
+
height="30"
|
|
5
|
+
style={{
|
|
6
|
+
marginRight: '10px',
|
|
7
|
+
marginBottom: '2px',
|
|
8
|
+
stroke: 'transparent',
|
|
9
|
+
strokeWidth: '0px',
|
|
10
|
+
}}
|
|
11
|
+
viewBox="0 0 83 83"
|
|
12
|
+
fill="none"
|
|
13
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
14
|
+
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
15
|
+
>
|
|
16
|
+
<rect width="83" height="83" fill="url(#pattern0)" />
|
|
17
|
+
<rect width="83" height="83" stroke="black" />
|
|
18
|
+
<defs>
|
|
19
|
+
<pattern
|
|
20
|
+
id="pattern0"
|
|
21
|
+
patternContentUnits="objectBoundingBox"
|
|
22
|
+
width="1"
|
|
23
|
+
height="1"
|
|
24
|
+
>
|
|
25
|
+
<use xlinkHref="#image0_1_2" transform="scale(0.00364964)" />
|
|
26
|
+
</pattern>
|
|
27
|
+
<image
|
|
28
|
+
id="image0_1_2"
|
|
29
|
+
width="274"
|
|
30
|
+
height="274"
|
|
31
|
+
xlinkHref="data:image/png;base64,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"
|
|
32
|
+
/>
|
|
33
|
+
</defs>
|
|
34
|
+
</svg>
|
|
35
|
+
);
|
|
36
|
+
export default DJLogo;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const DeleteIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
className="feather feather-trash-2"
|
|
4
|
+
fill="none"
|
|
5
|
+
height="24"
|
|
6
|
+
stroke="currentColor"
|
|
7
|
+
strokeLinecap="round"
|
|
8
|
+
strokeLinejoin="round"
|
|
9
|
+
strokeWidth="2"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
width="24"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
>
|
|
14
|
+
<polyline points="3 6 5 6 21 6" />
|
|
15
|
+
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
|
|
16
|
+
<line x1="10" x2="10" y1="11" y2="17" />
|
|
17
|
+
<line x1="14" x2="14" y1="11" y2="17" />
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export default DeleteIcon;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const EditIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
className="feather feather-edit"
|
|
4
|
+
fill="none"
|
|
5
|
+
height="24"
|
|
6
|
+
stroke="currentColor"
|
|
7
|
+
strokeLinecap="round"
|
|
8
|
+
strokeLinejoin="round"
|
|
9
|
+
strokeWidth="2"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
width="24"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
>
|
|
14
|
+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
|
15
|
+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
|
|
16
|
+
</svg>
|
|
17
|
+
);
|
|
18
|
+
export default EditIcon;
|
|
@@ -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;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This component is the skeleton around the actual pages, and only contains
|
|
3
|
+
* components that should be seen on all pages, like the logo or navigation bar.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import { Helmet } from 'react-helmet-async';
|
|
8
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
9
|
+
|
|
10
|
+
import { NamespacePage } from './pages/NamespacePage/Loadable';
|
|
11
|
+
import { NodePage } from './pages/NodePage/Loadable';
|
|
12
|
+
import { SQLBuilderPage } from './pages/SQLBuilderPage/Loadable';
|
|
13
|
+
import { TagPage } from './pages/TagPage/Loadable';
|
|
14
|
+
import { AddEditNodePage } from './pages/AddEditNodePage/Loadable';
|
|
15
|
+
import { AddEditTagPage } from './pages/AddEditTagPage/Loadable';
|
|
16
|
+
import { NotFoundPage } from './pages/NotFoundPage/Loadable';
|
|
17
|
+
import { LoginPage } from './pages/LoginPage';
|
|
18
|
+
import { RegisterTablePage } from './pages/RegisterTablePage';
|
|
19
|
+
import { Root } from './pages/Root/Loadable';
|
|
20
|
+
import DJClientContext from './providers/djclient';
|
|
21
|
+
import { DataJunctionAPI } from './services/DJService';
|
|
22
|
+
import { CookiesProvider, useCookies } from 'react-cookie';
|
|
23
|
+
import * as Constants from './constants';
|
|
24
|
+
|
|
25
|
+
export function App() {
|
|
26
|
+
const [cookies] = useCookies([Constants.LOGGED_IN_FLAG_COOKIE]);
|
|
27
|
+
return (
|
|
28
|
+
<CookiesProvider>
|
|
29
|
+
<BrowserRouter>
|
|
30
|
+
{cookies.__djlif || process.env.REACT_DISABLE_AUTH === 'true' ? (
|
|
31
|
+
<>
|
|
32
|
+
<Helmet
|
|
33
|
+
titleTemplate="DataJunction: %s"
|
|
34
|
+
defaultTitle="DataJunction: A Metrics Platform"
|
|
35
|
+
>
|
|
36
|
+
<meta
|
|
37
|
+
name="description"
|
|
38
|
+
content="DataJunction serves as a semantic layer to help manage metrics"
|
|
39
|
+
/>
|
|
40
|
+
</Helmet>
|
|
41
|
+
<DJClientContext.Provider value={{ DataJunctionAPI }}>
|
|
42
|
+
<Routes>
|
|
43
|
+
<Route
|
|
44
|
+
path="/"
|
|
45
|
+
element={<Root />}
|
|
46
|
+
children={
|
|
47
|
+
<>
|
|
48
|
+
<Route path="nodes" key="nodes">
|
|
49
|
+
<Route path=":name" element={<NodePage />} />
|
|
50
|
+
<Route
|
|
51
|
+
path=":name/edit"
|
|
52
|
+
key="edit"
|
|
53
|
+
element={<AddEditNodePage />}
|
|
54
|
+
/>
|
|
55
|
+
</Route>
|
|
56
|
+
|
|
57
|
+
<Route path="/" element={<NamespacePage />} key="index" />
|
|
58
|
+
<Route path="namespaces">
|
|
59
|
+
<Route
|
|
60
|
+
path=":namespace"
|
|
61
|
+
element={<NamespacePage />}
|
|
62
|
+
key="namespaces"
|
|
63
|
+
/>
|
|
64
|
+
</Route>
|
|
65
|
+
<Route
|
|
66
|
+
path="create/tag"
|
|
67
|
+
key="createtag"
|
|
68
|
+
element={<AddEditTagPage />}
|
|
69
|
+
></Route>
|
|
70
|
+
<Route
|
|
71
|
+
path="create/source"
|
|
72
|
+
key="register"
|
|
73
|
+
element={<RegisterTablePage />}
|
|
74
|
+
></Route>
|
|
75
|
+
<Route path="create/:nodeType">
|
|
76
|
+
<Route
|
|
77
|
+
path=":initialNamespace"
|
|
78
|
+
key="create"
|
|
79
|
+
element={<AddEditNodePage />}
|
|
80
|
+
/>
|
|
81
|
+
<Route
|
|
82
|
+
path=""
|
|
83
|
+
key="create"
|
|
84
|
+
element={<AddEditNodePage />}
|
|
85
|
+
/>
|
|
86
|
+
</Route>
|
|
87
|
+
<Route
|
|
88
|
+
path="sql"
|
|
89
|
+
key="sql"
|
|
90
|
+
element={<SQLBuilderPage />}
|
|
91
|
+
/>
|
|
92
|
+
<Route path="tags" key="tags">
|
|
93
|
+
<Route path=":name" element={<TagPage />} />
|
|
94
|
+
</Route>
|
|
95
|
+
</>
|
|
96
|
+
}
|
|
97
|
+
/>
|
|
98
|
+
<Route path="*" element={<NotFoundPage />} />
|
|
99
|
+
</Routes>
|
|
100
|
+
</DJClientContext.Provider>
|
|
101
|
+
</>
|
|
102
|
+
) : (
|
|
103
|
+
<LoginPage />
|
|
104
|
+
)}
|
|
105
|
+
</BrowserRouter>
|
|
106
|
+
</CookiesProvider>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A React Select component for use in Formik forms.
|
|
3
|
+
*/
|
|
4
|
+
import { useField } from 'formik';
|
|
5
|
+
import Select from 'react-select';
|
|
6
|
+
|
|
7
|
+
export const FormikSelect = ({
|
|
8
|
+
selectOptions,
|
|
9
|
+
formikFieldName,
|
|
10
|
+
placeholder,
|
|
11
|
+
defaultValue,
|
|
12
|
+
style,
|
|
13
|
+
className = 'SelectInput',
|
|
14
|
+
isMulti = false,
|
|
15
|
+
}) => {
|
|
16
|
+
// eslint-disable-next-line no-unused-vars
|
|
17
|
+
const [field, _, helpers] = useField(formikFieldName);
|
|
18
|
+
const { setValue } = helpers;
|
|
19
|
+
|
|
20
|
+
// handles both multi-select and single-select cases
|
|
21
|
+
const getValue = options => {
|
|
22
|
+
if (options) {
|
|
23
|
+
return isMulti ? options.map(option => option.value) : options.value;
|
|
24
|
+
} else {
|
|
25
|
+
return isMulti ? [] : '';
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Select
|
|
31
|
+
className={className}
|
|
32
|
+
defaultValue={defaultValue}
|
|
33
|
+
options={selectOptions}
|
|
34
|
+
name={field.name}
|
|
35
|
+
placeholder={placeholder}
|
|
36
|
+
onBlur={field.onBlur}
|
|
37
|
+
onChange={selected => setValue(getValue(selected))}
|
|
38
|
+
styles={style}
|
|
39
|
+
isMulti={isMulti}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
FormikSelect.defaultProps = {
|
|
45
|
+
placeholder: '',
|
|
46
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A field for the full node name, which is generated based on the node's input
|
|
3
|
+
* namespace and display name.
|
|
4
|
+
*/
|
|
5
|
+
import { useField, useFormikContext } from 'formik';
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
|
|
8
|
+
export const FullNameField = props => {
|
|
9
|
+
const { values, setFieldValue } = useFormikContext();
|
|
10
|
+
const [field, meta] = useField(props);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
// Set the value of the node's full name based on its namespace and display name
|
|
14
|
+
if (values.namespace && values.display_name) {
|
|
15
|
+
setFieldValue(
|
|
16
|
+
props.name,
|
|
17
|
+
`${values.namespace}.${values.display_name
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/ /g, '_')}` || '',
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
}, [setFieldValue, props.name, values]);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
<input
|
|
27
|
+
{...props}
|
|
28
|
+
{...field}
|
|
29
|
+
className="FullNameField"
|
|
30
|
+
disabled="disabled"
|
|
31
|
+
id="FullName"
|
|
32
|
+
value={values.name || ''}
|
|
33
|
+
/>
|
|
34
|
+
{!!meta.touched && !!meta.error && <div>{meta.error}</div>}
|
|
35
|
+
</>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asynchronously loads the component for the Node page
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { lazyLoad } from '../../../utils/loadable';
|
|
7
|
+
|
|
8
|
+
export const AddEditNodePage = () => {
|
|
9
|
+
return lazyLoad(
|
|
10
|
+
() => import('./index'),
|
|
11
|
+
module => module.AddEditNodePage,
|
|
12
|
+
{
|
|
13
|
+
fallback: <div></div>,
|
|
14
|
+
},
|
|
15
|
+
)();
|
|
16
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQL query input field, which consists of a CodeMirror SQL editor with autocompletion
|
|
3
|
+
* (for node names and columns) and syntax highlighting.
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { Field, useFormikContext } from 'formik';
|
|
7
|
+
import CodeMirror from '@uiw/react-codemirror';
|
|
8
|
+
import { langs } from '@uiw/codemirror-extensions-langs';
|
|
9
|
+
|
|
10
|
+
export const NodeQueryField = ({ djClient, value }) => {
|
|
11
|
+
const [schema, setSchema] = React.useState([]);
|
|
12
|
+
const formik = useFormikContext();
|
|
13
|
+
const sqlExt = langs.sql({ schema: schema });
|
|
14
|
+
|
|
15
|
+
const initialAutocomplete = async context => {
|
|
16
|
+
// Based on the parsed prefix, we load node names with that prefix
|
|
17
|
+
// into the autocomplete schema. At this stage we don't load the columns
|
|
18
|
+
// to save on unnecessary calls
|
|
19
|
+
const word = context.matchBefore(/[\.\w]*/);
|
|
20
|
+
const matches = await djClient.nodes(word.text);
|
|
21
|
+
matches.forEach(nodeName => {
|
|
22
|
+
if (schema[nodeName] === undefined) {
|
|
23
|
+
schema[nodeName] = [];
|
|
24
|
+
setSchema(schema);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const updateFormik = val => {
|
|
30
|
+
formik.setFieldValue('query', val);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const updateAutocomplete = async (value, _) => {
|
|
34
|
+
// If a particular node has been chosen, load the columns of that node into
|
|
35
|
+
// the autocomplete schema for column-level autocompletion
|
|
36
|
+
for (var nodeName in schema) {
|
|
37
|
+
if (
|
|
38
|
+
value.includes(nodeName) &&
|
|
39
|
+
(!schema.hasOwnProperty(nodeName) ||
|
|
40
|
+
(schema.hasOwnProperty(nodeName) && schema[nodeName].length === 0))
|
|
41
|
+
) {
|
|
42
|
+
const nodeDetails = await djClient.node(nodeName);
|
|
43
|
+
schema[nodeName] = nodeDetails.columns.map(col => col.name);
|
|
44
|
+
setSchema(schema);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
<Field
|
|
52
|
+
type="textarea"
|
|
53
|
+
style={{ display: 'none' }}
|
|
54
|
+
as="textarea"
|
|
55
|
+
name="query"
|
|
56
|
+
id="Query"
|
|
57
|
+
/>
|
|
58
|
+
<div role="button" tabIndex={0} className="relative flex bg-[#282a36]">
|
|
59
|
+
<CodeMirror
|
|
60
|
+
id={'query'}
|
|
61
|
+
name={'query'}
|
|
62
|
+
extensions={[
|
|
63
|
+
sqlExt,
|
|
64
|
+
sqlExt.language.data.of({
|
|
65
|
+
autocomplete: initialAutocomplete,
|
|
66
|
+
}),
|
|
67
|
+
]}
|
|
68
|
+
value={value}
|
|
69
|
+
options={{
|
|
70
|
+
theme: 'default',
|
|
71
|
+
lineNumbers: true,
|
|
72
|
+
}}
|
|
73
|
+
width="100%"
|
|
74
|
+
height="400px"
|
|
75
|
+
style={{
|
|
76
|
+
margin: '0 0 23px 0',
|
|
77
|
+
flex: 1,
|
|
78
|
+
fontSize: '150%',
|
|
79
|
+
textAlign: 'left',
|
|
80
|
+
}}
|
|
81
|
+
onChange={(value, viewUpdate) => {
|
|
82
|
+
updateFormik(value);
|
|
83
|
+
updateAutocomplete(value, viewUpdate);
|
|
84
|
+
}}
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
</>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { fireEvent, screen, waitFor } from '@testing-library/react';
|
|
3
|
+
import fetchMock from 'jest-fetch-mock';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
5
|
+
import {
|
|
6
|
+
initializeMockDJClient,
|
|
7
|
+
renderCreateNode,
|
|
8
|
+
renderEditNode,
|
|
9
|
+
testElement,
|
|
10
|
+
} from './index.test';
|
|
11
|
+
import { mocks } from '../../../../mocks/mockNodes';
|
|
12
|
+
|
|
13
|
+
describe('AddEditNodePage submission failed', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
fetchMock.resetMocks();
|
|
16
|
+
jest.clearAllMocks();
|
|
17
|
+
window.scrollTo = jest.fn();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('for creating a node', async () => {
|
|
21
|
+
const mockDjClient = initializeMockDJClient();
|
|
22
|
+
mockDjClient.DataJunctionAPI.createNode.mockReturnValue({
|
|
23
|
+
status: 500,
|
|
24
|
+
json: { message: 'Some columns in the primary key [] were not found' },
|
|
25
|
+
});
|
|
26
|
+
mockDjClient.DataJunctionAPI.listTags.mockReturnValue([
|
|
27
|
+
{ name: 'purpose', display_name: 'Purpose' },
|
|
28
|
+
{ name: 'intent', display_name: 'Intent' },
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const element = testElement(mockDjClient);
|
|
32
|
+
const { container } = renderCreateNode(element);
|
|
33
|
+
|
|
34
|
+
await userEvent.type(
|
|
35
|
+
screen.getByLabelText('Display Name'),
|
|
36
|
+
'Some Test Metric',
|
|
37
|
+
);
|
|
38
|
+
await userEvent.type(screen.getByLabelText('Query'), 'SELECT * FROM test');
|
|
39
|
+
await userEvent.click(screen.getByText('Create dimension'));
|
|
40
|
+
|
|
41
|
+
await waitFor(() => {
|
|
42
|
+
expect(mockDjClient.DataJunctionAPI.createNode).toBeCalled();
|
|
43
|
+
expect(mockDjClient.DataJunctionAPI.createNode).toBeCalledWith(
|
|
44
|
+
'dimension',
|
|
45
|
+
'default.some_test_metric',
|
|
46
|
+
'Some Test Metric',
|
|
47
|
+
'',
|
|
48
|
+
'SELECT * FROM test',
|
|
49
|
+
'draft',
|
|
50
|
+
'default',
|
|
51
|
+
null,
|
|
52
|
+
);
|
|
53
|
+
expect(
|
|
54
|
+
screen.getByText(/Some columns in the primary key \[] were not found/),
|
|
55
|
+
).toBeInTheDocument();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// After failed creation, it should return a failure message
|
|
59
|
+
expect(container.getElementsByClassName('alert')).toMatchSnapshot();
|
|
60
|
+
}, 60000);
|
|
61
|
+
|
|
62
|
+
it('for editing a node', async () => {
|
|
63
|
+
const mockDjClient = initializeMockDJClient();
|
|
64
|
+
mockDjClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
|
|
65
|
+
mockDjClient.DataJunctionAPI.patchNode.mockReturnValue({
|
|
66
|
+
status: 500,
|
|
67
|
+
json: { message: 'Update failed' },
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
mockDjClient.DataJunctionAPI.tagsNode.mockReturnValue({
|
|
71
|
+
status: 404,
|
|
72
|
+
json: { message: 'Some tags were not found' },
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
mockDjClient.DataJunctionAPI.listTags.mockReturnValue([
|
|
76
|
+
{ name: 'purpose', display_name: 'Purpose' },
|
|
77
|
+
{ name: 'intent', display_name: 'Intent' },
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
const element = testElement(mockDjClient);
|
|
81
|
+
renderEditNode(element);
|
|
82
|
+
|
|
83
|
+
await userEvent.type(screen.getByLabelText('Display Name'), '!!!');
|
|
84
|
+
await userEvent.type(screen.getByLabelText('Description'), '!!!');
|
|
85
|
+
await userEvent.click(screen.getByText('Save'));
|
|
86
|
+
await waitFor(async () => {
|
|
87
|
+
expect(mockDjClient.DataJunctionAPI.patchNode).toBeCalledTimes(1);
|
|
88
|
+
expect(mockDjClient.DataJunctionAPI.tagsNode).toBeCalled();
|
|
89
|
+
expect(mockDjClient.DataJunctionAPI.tagsNode).toBeCalledWith(
|
|
90
|
+
'default.num_repair_orders',
|
|
91
|
+
[{ display_name: 'Purpose', name: 'purpose' }],
|
|
92
|
+
);
|
|
93
|
+
expect(mockDjClient.DataJunctionAPI.tagsNode).toReturnWith({
|
|
94
|
+
json: { message: 'Some tags were not found' },
|
|
95
|
+
status: 404,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(
|
|
99
|
+
await screen.getByText('Update failed, Some tags were not found'),
|
|
100
|
+
).toBeInTheDocument();
|
|
101
|
+
});
|
|
102
|
+
}, 60000);
|
|
103
|
+
});
|