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
package/.github/workflows/ci.yml
CHANGED
|
@@ -2,9 +2,9 @@ name: CI/CD
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
-
branches: [
|
|
5
|
+
branches: [main]
|
|
6
6
|
pull_request:
|
|
7
|
-
branches: [
|
|
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
|
|
22
|
+
uses: actions/setup-node@v3
|
|
23
23
|
with:
|
|
24
24
|
node-version: ${{ matrix.node-version }}
|
|
25
25
|
|
package/.prettierignore
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datajunction-ui",
|
|
3
|
-
"version": "0.0.1-rc.
|
|
3
|
+
"version": "0.0.1-rc.11",
|
|
4
4
|
"description": "DataJunction Metrics Platform UI",
|
|
5
5
|
"module": "src/index.tsx",
|
|
6
6
|
"repository": {
|
|
@@ -32,20 +32,21 @@
|
|
|
32
32
|
"@types/react": "^18.0.20",
|
|
33
33
|
"@types/react-dom": "^18.0.6",
|
|
34
34
|
"@types/react-redux": "^7.1.24",
|
|
35
|
+
"@types/react-select": "5.0.1",
|
|
35
36
|
"@types/react-test-renderer": "^18.0.0",
|
|
36
37
|
"@types/rimraf": "^3.0.2",
|
|
37
38
|
"@types/shelljs": "^0.8.11",
|
|
38
39
|
"@types/testing-library__jest-dom": "^5.14.5",
|
|
39
40
|
"@types/webpack": "^5.28.0",
|
|
40
41
|
"@types/webpack-env": "^1.18.0",
|
|
42
|
+
"babel-loader": "9.1.2",
|
|
41
43
|
"chalk": "4.1.2",
|
|
44
|
+
"cronstrue": "2.27.0",
|
|
42
45
|
"cross-env": "7.0.3",
|
|
46
|
+
"css-loader": "6.7.3",
|
|
43
47
|
"dagre": "^0.8.5",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"eslint-plugin-react-hooks": "4.6.0",
|
|
47
|
-
"fbemitter": "3.0.0",
|
|
48
|
-
"flux": "4.0.4",
|
|
48
|
+
"datajunction": "0.0.1-rc.0",
|
|
49
|
+
"file-loader": "6.2.0",
|
|
49
50
|
"fontfaceobserver": "2.3.0",
|
|
50
51
|
"husky": "8.0.1",
|
|
51
52
|
"i18next": "21.9.2",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"react-redux": "7.2.8",
|
|
67
68
|
"react-router-dom": "6.3.0",
|
|
68
69
|
"react-scripts": "5.0.1",
|
|
70
|
+
"react-select": "5.7.3",
|
|
69
71
|
"react-syntax-highlighter": "^15.5.0",
|
|
70
72
|
"react-test-renderer": "18.2.0",
|
|
71
73
|
"reactflow": "^11.7.0",
|
|
@@ -76,6 +78,7 @@
|
|
|
76
78
|
"serve": "14.0.1",
|
|
77
79
|
"shelljs": "0.8.5",
|
|
78
80
|
"sql-formatter": "^12.2.0",
|
|
81
|
+
"style-loader": "3.3.2",
|
|
79
82
|
"stylelint": "14.12.0",
|
|
80
83
|
"stylelint-config-recommended": "9.0.0",
|
|
81
84
|
"ts-loader": "9.4.2",
|
|
@@ -83,7 +86,8 @@
|
|
|
83
86
|
"typescript": "4.6.4",
|
|
84
87
|
"web-vitals": "2.1.4",
|
|
85
88
|
"webpack": "5.81.0",
|
|
86
|
-
"webpack-cli": "5.0.2"
|
|
89
|
+
"webpack-cli": "5.0.2",
|
|
90
|
+
"webpack-dev-server": "4.13.3"
|
|
87
91
|
},
|
|
88
92
|
"scripts": {
|
|
89
93
|
"webpack-start": "webpack-dev-server --open",
|
|
@@ -102,7 +106,8 @@
|
|
|
102
106
|
"generate": "plop --plopfile internals/generators/plopfile.ts",
|
|
103
107
|
"cleanAndSetup": "ts-node ./internals/scripts/clean.ts",
|
|
104
108
|
"prettify": "prettier --write",
|
|
105
|
-
"extract-messages": "i18next-scanner --config=internals/extractMessages/i18next-scanner.config.js"
|
|
109
|
+
"extract-messages": "i18next-scanner --config=internals/extractMessages/i18next-scanner.config.js",
|
|
110
|
+
"prepublishOnly": "webpack --mode=production"
|
|
106
111
|
},
|
|
107
112
|
"eslintConfig": {
|
|
108
113
|
"extends": "react-app"
|
|
@@ -150,6 +155,9 @@
|
|
|
150
155
|
},
|
|
151
156
|
"devDependencies": {
|
|
152
157
|
"@babel/plugin-proposal-class-properties": "7.18.6",
|
|
158
|
+
"eslint-config-prettier": "8.8.0",
|
|
159
|
+
"eslint-plugin-prettier": "4.2.1",
|
|
160
|
+
"eslint-plugin-react-hooks": "4.6.0",
|
|
153
161
|
"html-webpack-plugin": "5.5.1",
|
|
154
162
|
"jest": "^29.5.0",
|
|
155
163
|
"mini-css-extract-plugin": "2.7.5"
|
|
@@ -14,30 +14,72 @@ exports[`<App /> should render and match the snapshot 1`] = `
|
|
|
14
14
|
name="description"
|
|
15
15
|
/>
|
|
16
16
|
</Helmet>
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
17
|
+
<Context.Provider
|
|
18
|
+
value={
|
|
19
|
+
Object {
|
|
20
|
+
"DataJunctionAPI": Object {
|
|
21
|
+
"clientCode": [Function],
|
|
22
|
+
"columns": [Function],
|
|
23
|
+
"commonDimensions": [Function],
|
|
24
|
+
"compiledSql": [Function],
|
|
25
|
+
"cube": [Function],
|
|
26
|
+
"dag": [Function],
|
|
27
|
+
"data": [Function],
|
|
28
|
+
"downstreams": [Function],
|
|
29
|
+
"history": [Function],
|
|
30
|
+
"lineage": [Function],
|
|
31
|
+
"materializations": [Function],
|
|
32
|
+
"metric": [Function],
|
|
33
|
+
"metrics": [Function],
|
|
34
|
+
"namespace": [Function],
|
|
35
|
+
"namespaces": [Function],
|
|
36
|
+
"node": [Function],
|
|
37
|
+
"node_dag": [Function],
|
|
38
|
+
"revisions": [Function],
|
|
39
|
+
"sql": [Function],
|
|
40
|
+
"sqls": [Function],
|
|
41
|
+
"upstreams": [Function],
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
>
|
|
46
|
+
<Routes>
|
|
47
|
+
<Route
|
|
48
|
+
element={<Unknown />}
|
|
49
|
+
path="/"
|
|
50
|
+
>
|
|
51
|
+
<React.Fragment>
|
|
52
|
+
<Route
|
|
53
|
+
path="nodes"
|
|
54
|
+
>
|
|
55
|
+
<Route
|
|
56
|
+
element={<NodePage />}
|
|
57
|
+
path=":name"
|
|
58
|
+
/>
|
|
59
|
+
</Route>
|
|
60
|
+
<Route
|
|
61
|
+
element={<NamespacePage />}
|
|
62
|
+
path="/"
|
|
63
|
+
/>
|
|
64
|
+
<Route
|
|
65
|
+
path="namespaces"
|
|
66
|
+
>
|
|
67
|
+
<Route
|
|
68
|
+
element={<NamespacePage />}
|
|
69
|
+
path=":namespace"
|
|
70
|
+
/>
|
|
71
|
+
</Route>
|
|
72
|
+
<Route
|
|
73
|
+
element={<SQLBuilderPage />}
|
|
74
|
+
path="sql"
|
|
75
|
+
/>
|
|
76
|
+
</React.Fragment>
|
|
77
|
+
</Route>
|
|
78
|
+
<Route
|
|
79
|
+
element={<Unknown />}
|
|
80
|
+
path="*"
|
|
81
|
+
/>
|
|
82
|
+
</Routes>
|
|
83
|
+
</Context.Provider>
|
|
42
84
|
</BrowserRouter>
|
|
43
85
|
`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Component } from 'react';
|
|
2
|
+
import HorizontalHierarchyIcon from '../icons/HorizontalHierarchyIcon';
|
|
2
3
|
|
|
3
4
|
export default class NamespaceHeader extends Component {
|
|
4
5
|
render() {
|
|
@@ -6,7 +7,7 @@ export default class NamespaceHeader extends Component {
|
|
|
6
7
|
const namespaceParts = namespace.split('.');
|
|
7
8
|
const namespaceList = namespaceParts.map((piece, index) => {
|
|
8
9
|
return (
|
|
9
|
-
<li className="breadcrumb-item">
|
|
10
|
+
<li className="breadcrumb-item" key={index}>
|
|
10
11
|
<a
|
|
11
12
|
className="link-body-emphasis"
|
|
12
13
|
href={'/namespaces/' + namespaceParts.slice(0, index + 1).join('.')}
|
|
@@ -19,18 +20,8 @@ export default class NamespaceHeader extends Component {
|
|
|
19
20
|
return (
|
|
20
21
|
<ol className="breadcrumb breadcrumb-chevron p-3 bg-body-tertiary rounded-3">
|
|
21
22
|
<li className="breadcrumb-item">
|
|
22
|
-
<a href="/
|
|
23
|
-
<
|
|
24
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
25
|
-
width="16"
|
|
26
|
-
height="16"
|
|
27
|
-
fill="currentColor"
|
|
28
|
-
className="bi bi-house-door-fill"
|
|
29
|
-
viewBox="0 0 16 16"
|
|
30
|
-
style={{ paddingBottom: '0.2rem' }}
|
|
31
|
-
>
|
|
32
|
-
<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" />
|
|
33
|
-
</svg>
|
|
23
|
+
<a href="/">
|
|
24
|
+
<HorizontalHierarchyIcon />
|
|
34
25
|
</a>
|
|
35
26
|
</li>
|
|
36
27
|
{namespaceList}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export default function QueryInfo({
|
|
2
|
+
id,
|
|
3
|
+
state,
|
|
4
|
+
engine_name,
|
|
5
|
+
engine_version,
|
|
6
|
+
errors,
|
|
7
|
+
links,
|
|
8
|
+
output_table,
|
|
9
|
+
scheduled,
|
|
10
|
+
started,
|
|
11
|
+
numRows,
|
|
12
|
+
}) {
|
|
13
|
+
const stateIcon =
|
|
14
|
+
state === 'FINISHED' ? (
|
|
15
|
+
<span className="status__valid status" style={{ alignContent: 'center' }}>
|
|
16
|
+
<svg
|
|
17
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
18
|
+
width="25"
|
|
19
|
+
height="25"
|
|
20
|
+
fill="currentColor"
|
|
21
|
+
className="bi bi-check-circle-fill"
|
|
22
|
+
viewBox="0 0 16 16"
|
|
23
|
+
>
|
|
24
|
+
<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" />
|
|
25
|
+
</svg>
|
|
26
|
+
</span>
|
|
27
|
+
) : (
|
|
28
|
+
<span
|
|
29
|
+
className="status__invalid status"
|
|
30
|
+
style={{ alignContent: 'center' }}
|
|
31
|
+
>
|
|
32
|
+
<svg
|
|
33
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
34
|
+
width="16"
|
|
35
|
+
height="16"
|
|
36
|
+
fill="currentColor"
|
|
37
|
+
className="bi bi-x-circle-fill"
|
|
38
|
+
viewBox="0 0 16 16"
|
|
39
|
+
>
|
|
40
|
+
<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" />
|
|
41
|
+
</svg>
|
|
42
|
+
</span>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div className="table-responsive">
|
|
47
|
+
<table className="card-inner-table table">
|
|
48
|
+
<thead className="fs-7 fw-bold text-gray-400 border-bottom-0">
|
|
49
|
+
<tr>
|
|
50
|
+
<th>Query ID</th>
|
|
51
|
+
<th>Engine</th>
|
|
52
|
+
<th>State</th>
|
|
53
|
+
<th>Scheduled</th>
|
|
54
|
+
<th>Started</th>
|
|
55
|
+
<th>Errors</th>
|
|
56
|
+
<th>Links</th>
|
|
57
|
+
<th>Output Table</th>
|
|
58
|
+
<th>Number of Rows</th>
|
|
59
|
+
</tr>
|
|
60
|
+
</thead>
|
|
61
|
+
<tbody>
|
|
62
|
+
<tr>
|
|
63
|
+
<td>
|
|
64
|
+
<span className="rounded-pill badge bg-secondary-soft">{id}</span>
|
|
65
|
+
</td>
|
|
66
|
+
<td>
|
|
67
|
+
<span className="rounded-pill badge bg-secondary-soft">
|
|
68
|
+
{engine_name}
|
|
69
|
+
{' - '}
|
|
70
|
+
{engine_version}
|
|
71
|
+
</span>
|
|
72
|
+
</td>
|
|
73
|
+
<td>{stateIcon}</td>
|
|
74
|
+
<td>{scheduled}</td>
|
|
75
|
+
<td>{started}</td>
|
|
76
|
+
<td>
|
|
77
|
+
{errors.length ? (
|
|
78
|
+
errors.map(e => (
|
|
79
|
+
<p>
|
|
80
|
+
<span className="rounded-pill badge bg-secondary-error">
|
|
81
|
+
{e}
|
|
82
|
+
</span>
|
|
83
|
+
</p>
|
|
84
|
+
))
|
|
85
|
+
) : (
|
|
86
|
+
<></>
|
|
87
|
+
)}
|
|
88
|
+
</td>
|
|
89
|
+
<td>
|
|
90
|
+
{links?.length ? (
|
|
91
|
+
links.map(link => (
|
|
92
|
+
<p>
|
|
93
|
+
<a href={link} target="_blank" rel="noreferrer">
|
|
94
|
+
{link}
|
|
95
|
+
</a>
|
|
96
|
+
</p>
|
|
97
|
+
))
|
|
98
|
+
) : (
|
|
99
|
+
<></>
|
|
100
|
+
)}
|
|
101
|
+
</td>
|
|
102
|
+
<td>{output_table}</td>
|
|
103
|
+
<td>{numRows}</td>
|
|
104
|
+
</tr>
|
|
105
|
+
</tbody>
|
|
106
|
+
</table>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
@@ -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>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
const ToggleSwitch = ({ checked, onChange, toggleName }) => (
|
|
4
|
+
<>
|
|
5
|
+
<input
|
|
6
|
+
id="show-compiled-sql-toggle"
|
|
7
|
+
type="checkbox"
|
|
8
|
+
className="checkbox"
|
|
9
|
+
checked={checked}
|
|
10
|
+
onChange={e => onChange(e.target.checked)}
|
|
11
|
+
/>
|
|
12
|
+
<label htmlFor="show-compiled-sql-toggle" className="switch"></label>{' '}
|
|
13
|
+
{toggleName}
|
|
14
|
+
</>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export default ToggleSwitch;
|
|
@@ -8,25 +8,9 @@ exports[`<NamespaceHeader /> should render and match the snapshot 1`] = `
|
|
|
8
8
|
className="breadcrumb-item"
|
|
9
9
|
>
|
|
10
10
|
<a
|
|
11
|
-
href="/
|
|
11
|
+
href="/"
|
|
12
12
|
>
|
|
13
|
-
<
|
|
14
|
-
className="bi bi-house-door-fill"
|
|
15
|
-
fill="currentColor"
|
|
16
|
-
height="16"
|
|
17
|
-
style={
|
|
18
|
-
Object {
|
|
19
|
-
"paddingBottom": "0.2rem",
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
viewBox="0 0 16 16"
|
|
23
|
-
width="16"
|
|
24
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
25
|
-
>
|
|
26
|
-
<path
|
|
27
|
-
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"
|
|
28
|
-
/>
|
|
29
|
-
</svg>
|
|
13
|
+
<HorizontalHierarchyIcon />
|
|
30
14
|
</a>
|
|
31
15
|
</li>
|
|
32
16
|
<li
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DJNodeDimensions } from './DJNodeDimensions';
|
|
3
|
+
import { DJNodeColumns } from './DJNodeColumns';
|
|
4
|
+
|
|
5
|
+
export default function Collapse({ collapsed, text, data }) {
|
|
6
|
+
const [isCollapsed, setIsCollapsed] = React.useState(collapsed);
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<div className="collapse">
|
|
11
|
+
{data.type === 'metric' ? (
|
|
12
|
+
<button
|
|
13
|
+
className="collapse-button"
|
|
14
|
+
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
15
|
+
>
|
|
16
|
+
{isCollapsed ? '\u25B6 Show' : '\u25BC Hide'} {text}
|
|
17
|
+
</button>
|
|
18
|
+
) : (
|
|
19
|
+
''
|
|
20
|
+
)}
|
|
21
|
+
<div
|
|
22
|
+
className={`collapse-content ${
|
|
23
|
+
isCollapsed && data.type === 'metric' ? 'collapsed' : 'expanded'
|
|
24
|
+
}`}
|
|
25
|
+
aria-expanded={isCollapsed}
|
|
26
|
+
>
|
|
27
|
+
{data.type !== 'metric'
|
|
28
|
+
? isCollapsed
|
|
29
|
+
? DJNodeColumns({ data: data, limit: 10 })
|
|
30
|
+
: DJNodeColumns({ data: data, limit: 100 })
|
|
31
|
+
: DJNodeDimensions(data)}
|
|
32
|
+
</div>
|
|
33
|
+
{data.type !== 'metric' && data.column_names.length > 10 ? (
|
|
34
|
+
<button
|
|
35
|
+
className="collapse-button"
|
|
36
|
+
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
37
|
+
>
|
|
38
|
+
{isCollapsed ? '\u25B6 More' : '\u25BC Less'} {text}
|
|
39
|
+
</button>
|
|
40
|
+
) : (
|
|
41
|
+
''
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
</>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -1,81 +1,57 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
2
|
import { Handle, Position } from 'reactflow';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
switch (param) {
|
|
6
|
-
case 'source':
|
|
7
|
-
return { backgroundColor: '#7EB46150', color: '#7EB461' };
|
|
8
|
-
case 'transform':
|
|
9
|
-
return { backgroundColor: '#6DAAA750', color: '#6DAAA7' };
|
|
10
|
-
case 'dimension':
|
|
11
|
-
return { backgroundColor: '#CF7D2950', color: '#CF7D29' };
|
|
12
|
-
case 'metric':
|
|
13
|
-
return { backgroundColor: '#A27E8650', color: '#A27E86' };
|
|
14
|
-
case 'cube':
|
|
15
|
-
return { backgroundColor: '#C2180750', color: '#C21807' };
|
|
16
|
-
default:
|
|
17
|
-
return {};
|
|
18
|
-
}
|
|
19
|
-
}
|
|
3
|
+
import { DJNodeDimensions } from './DJNodeDimensions';
|
|
4
|
+
import Collapse from './Collapse';
|
|
20
5
|
|
|
21
6
|
function capitalize(string) {
|
|
22
7
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
23
8
|
}
|
|
24
9
|
|
|
25
|
-
const Collapse = ({ collapsed, text, children }) => {
|
|
26
|
-
const [isCollapsed, setIsCollapsed] = React.useState(collapsed);
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<>
|
|
30
|
-
<div className="collapse">
|
|
31
|
-
<button
|
|
32
|
-
className="collapse-button"
|
|
33
|
-
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
34
|
-
>
|
|
35
|
-
{isCollapsed ? '\u25B6 Show' : '\u25BC Hide'} {text}
|
|
36
|
-
</button>
|
|
37
|
-
<div
|
|
38
|
-
className={`collapse-content ${
|
|
39
|
-
isCollapsed ? 'collapsed' : 'expanded'
|
|
40
|
-
}`}
|
|
41
|
-
aria-expanded={isCollapsed}
|
|
42
|
-
>
|
|
43
|
-
{children}
|
|
44
|
-
</div>
|
|
45
|
-
</div>
|
|
46
|
-
</>
|
|
47
|
-
);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
10
|
export function DJNode({ id, data }) {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
</td>
|
|
61
|
-
<td style={{ textAlign: 'right' }}>{col.type}</td>
|
|
62
|
-
</tr>
|
|
63
|
-
));
|
|
64
|
-
const dimensionsRenderer = data =>
|
|
65
|
-
data.dimensions.map(dim => (
|
|
66
|
-
<tr>
|
|
67
|
-
<td>{dim}</td>
|
|
68
|
-
</tr>
|
|
69
|
-
));
|
|
11
|
+
const handleWrapperStyle = {
|
|
12
|
+
display: 'flex',
|
|
13
|
+
position: 'absolute',
|
|
14
|
+
height: '100%',
|
|
15
|
+
flexDirection: 'column',
|
|
16
|
+
top: '50%',
|
|
17
|
+
justifyContent: 'space-between',
|
|
18
|
+
};
|
|
19
|
+
const handleWrapperStyleRight = { ...handleWrapperStyle, ...{ right: 0 } };
|
|
70
20
|
|
|
21
|
+
const handleStyle = {
|
|
22
|
+
width: '12px',
|
|
23
|
+
height: '12px',
|
|
24
|
+
borderRadius: '12px',
|
|
25
|
+
background: 'transparent',
|
|
26
|
+
border: '4px solid transparent',
|
|
27
|
+
cursor: 'pointer',
|
|
28
|
+
position: 'absolute',
|
|
29
|
+
top: '0px',
|
|
30
|
+
left: 0,
|
|
31
|
+
};
|
|
32
|
+
const handleStyleLeft = percentage => {
|
|
33
|
+
return {
|
|
34
|
+
...handleStyle,
|
|
35
|
+
...{
|
|
36
|
+
transform: 'translate(-' + percentage + '%, -50%)',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const highlightNodeClass =
|
|
41
|
+
data.is_current === true ? ' dj-node_highlight' : '';
|
|
71
42
|
return (
|
|
72
43
|
<>
|
|
73
|
-
<
|
|
74
|
-
type
|
|
75
|
-
|
|
76
|
-
style={
|
|
77
|
-
|
|
78
|
-
|
|
44
|
+
<div
|
|
45
|
+
className={'dj-node__full node_type__' + data.type + highlightNodeClass}
|
|
46
|
+
>
|
|
47
|
+
<div style={handleWrapperStyle}>
|
|
48
|
+
<Handle
|
|
49
|
+
type="target"
|
|
50
|
+
id={data.name}
|
|
51
|
+
position={Position.Left}
|
|
52
|
+
style={handleStyleLeft(100)}
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
79
55
|
<div className="dj-node__header">
|
|
80
56
|
<div className="serif">
|
|
81
57
|
{data.name
|
|
@@ -86,24 +62,24 @@ export function DJNode({ id, data }) {
|
|
|
86
62
|
</div>
|
|
87
63
|
<div className="dj-node__body">
|
|
88
64
|
<b>{capitalize(data.type)}</b>:{' '}
|
|
89
|
-
{data.
|
|
65
|
+
<a href={`/nodes/${data.name}`}>
|
|
66
|
+
{data.type === 'source' ? data.table : data.display_name}
|
|
67
|
+
</a>
|
|
90
68
|
<Collapse
|
|
91
69
|
collapsed={true}
|
|
92
70
|
text={data.type !== 'metric' ? 'columns' : 'dimensions'}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
71
|
+
data={data}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
<div style={handleWrapperStyleRight}>
|
|
75
|
+
<Handle
|
|
76
|
+
type="source"
|
|
77
|
+
id={data.name}
|
|
78
|
+
position={Position.Right}
|
|
79
|
+
style={handleStyleLeft(90)}
|
|
80
|
+
/>
|
|
100
81
|
</div>
|
|
101
82
|
</div>
|
|
102
|
-
<Handle
|
|
103
|
-
type="source"
|
|
104
|
-
position={Position.Right}
|
|
105
|
-
style={{ backgroundColor: '#ccc' }}
|
|
106
|
-
/>
|
|
107
83
|
</>
|
|
108
84
|
);
|
|
109
85
|
}
|