datajunction-ui 0.0.1-a44.dev0 → 0.0.1-a44.dev2
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/package.json +2 -2
- package/src/app/components/djgraph/DJNode.jsx +1 -1
- package/src/app/pages/NodePage/AddMaterializationPopover.jsx +22 -24
- package/src/app/pages/NodePage/LinkDimensionPopover.jsx +8 -7
- package/src/app/pages/NodePage/MaterializationConfigField.jsx +53 -0
- package/src/app/pages/NodePage/NodeColumnTab.jsx +85 -72
- package/src/app/pages/NodePage/NodeGraphTab.jsx +26 -22
- package/src/app/pages/NodePage/NodeMaterializationTab.jsx +2 -1
- package/src/app/pages/NodePage/__tests__/AddMaterializationPopover.test.jsx +3 -0
- package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +3 -2
- package/src/app/pages/NodePage/__tests__/NodeColumnTab.test.jsx +4 -0
- package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +4 -0
- package/src/app/pages/Root/index.tsx +12 -4
- package/src/styles/index.css +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datajunction-ui",
|
|
3
|
-
"version": "0.0.1-a44.
|
|
3
|
+
"version": "0.0.1-a44.dev2",
|
|
4
4
|
"description": "DataJunction Metrics Platform UI",
|
|
5
5
|
"module": "src/index.tsx",
|
|
6
6
|
"repository": {
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
],
|
|
163
163
|
"coverageThreshold": {
|
|
164
164
|
"global": {
|
|
165
|
-
"statements":
|
|
165
|
+
"statements": 89,
|
|
166
166
|
"branches": 75,
|
|
167
167
|
"lines": 90,
|
|
168
168
|
"functions": 85
|
|
@@ -68,7 +68,7 @@ export function DJNode({ id, data }) {
|
|
|
68
68
|
{data.type === 'source' ? data.table : data.display_name}
|
|
69
69
|
</a>
|
|
70
70
|
<Collapse
|
|
71
|
-
collapsed={true}
|
|
71
|
+
collapsed={data.is_current && data.type != 'metric' ? false : true}
|
|
72
72
|
text={data.type !== 'metric' ? 'columns' : 'dimensions'}
|
|
73
73
|
data={data}
|
|
74
74
|
/>
|
|
@@ -3,6 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import DJClientContext from '../../providers/djclient';
|
|
4
4
|
import { ErrorMessage, Field, Form, Formik } from 'formik';
|
|
5
5
|
import { displayMessageAfterSubmit, labelize } from '../../../utils/form';
|
|
6
|
+
import {ConfigField} from "./MaterializationConfigField";
|
|
6
7
|
|
|
7
8
|
export default function AddMaterializationPopover({ node, onSubmit }) {
|
|
8
9
|
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
@@ -38,7 +39,8 @@ export default function AddMaterializationPopover({ node, onSubmit }) {
|
|
|
38
39
|
{ setSubmitting, setStatus },
|
|
39
40
|
) => {
|
|
40
41
|
setSubmitting(false);
|
|
41
|
-
const config =
|
|
42
|
+
const config = {};
|
|
43
|
+
config.spark = values.spark_config;
|
|
42
44
|
config.lookback_window = values.lookback_window;
|
|
43
45
|
const response = await djClient.materialize(
|
|
44
46
|
values.node,
|
|
@@ -48,13 +50,12 @@ export default function AddMaterializationPopover({ node, onSubmit }) {
|
|
|
48
50
|
config,
|
|
49
51
|
);
|
|
50
52
|
if (response.status === 200 || response.status === 201) {
|
|
51
|
-
setStatus({ success:
|
|
53
|
+
setStatus({ success: response.json.message });
|
|
52
54
|
} else {
|
|
53
55
|
setStatus({
|
|
54
56
|
failure: `${response.json.message}`,
|
|
55
57
|
});
|
|
56
58
|
}
|
|
57
|
-
onSubmit();
|
|
58
59
|
// window.location.reload();
|
|
59
60
|
};
|
|
60
61
|
|
|
@@ -87,11 +88,14 @@ export default function AddMaterializationPopover({ node, onSubmit }) {
|
|
|
87
88
|
<Formik
|
|
88
89
|
initialValues={{
|
|
89
90
|
node: node?.name,
|
|
90
|
-
job_type: 'spark_sql',
|
|
91
|
+
job_type: node?.type === 'cube' ? 'druid_cube' : 'spark_sql',
|
|
91
92
|
strategy: 'full',
|
|
92
|
-
config: '{"spark": {"spark.executor.memory": "6g"}}',
|
|
93
93
|
schedule: '@daily',
|
|
94
94
|
lookback_window: '1 DAY',
|
|
95
|
+
spark_config: {
|
|
96
|
+
"spark.executor.memory": "16g",
|
|
97
|
+
"spark.memory.fraction": "0.3"
|
|
98
|
+
},
|
|
95
99
|
}}
|
|
96
100
|
onSubmit={configureMaterialization}
|
|
97
101
|
>
|
|
@@ -104,11 +108,9 @@ export default function AddMaterializationPopover({ node, onSubmit }) {
|
|
|
104
108
|
<label htmlFor="job_type">Job Type</label>
|
|
105
109
|
<Field as="select" name="job_type">
|
|
106
110
|
<>
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
</option>
|
|
111
|
-
))}
|
|
111
|
+
<option key={'druid_measures_cube'} value={'druid_measures_cube'}>Druid Measures Cube (Pre-Agg Cube)</option>
|
|
112
|
+
<option key={'druid_metrics_cube'} value={'druid_metrics_cube'}>Druid Metrics Cube (Post-Agg Cube)</option>
|
|
113
|
+
<option key={'spark_sql'} value={'spark_sql'}>Iceberg Table</option>
|
|
112
114
|
</>
|
|
113
115
|
</Field>
|
|
114
116
|
</span>
|
|
@@ -124,9 +126,12 @@ export default function AddMaterializationPopover({ node, onSubmit }) {
|
|
|
124
126
|
<label htmlFor="strategy">Strategy</label>
|
|
125
127
|
<Field as="select" name="strategy">
|
|
126
128
|
<>
|
|
127
|
-
{
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
<option key={'full'} value={'full'}>
|
|
130
|
+
Full
|
|
131
|
+
</option>
|
|
132
|
+
<option key={'incremental_time'} value={'incremental_time'}>
|
|
133
|
+
Incremental Time
|
|
134
|
+
</option>
|
|
130
135
|
</>
|
|
131
136
|
</Field>
|
|
132
137
|
</span>
|
|
@@ -154,17 +159,10 @@ export default function AddMaterializationPopover({ node, onSubmit }) {
|
|
|
154
159
|
/>
|
|
155
160
|
</div>
|
|
156
161
|
<br />
|
|
157
|
-
<
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
type="textarea"
|
|
162
|
-
as="textarea"
|
|
163
|
-
name="config"
|
|
164
|
-
id="Config"
|
|
165
|
-
placeholder="Optional engine-specific configuration (i.e., Spark conf etc)"
|
|
166
|
-
/>
|
|
167
|
-
</div>
|
|
162
|
+
<ConfigField value={{
|
|
163
|
+
"spark.executor.memory": "16g",
|
|
164
|
+
"spark.memory.fraction": "0.3"
|
|
165
|
+
}}/>
|
|
168
166
|
<button
|
|
169
167
|
className="add_node"
|
|
170
168
|
type="submit"
|
|
@@ -8,6 +8,7 @@ import { displayMessageAfterSubmit } from '../../../utils/form';
|
|
|
8
8
|
|
|
9
9
|
export default function LinkDimensionPopover({
|
|
10
10
|
column,
|
|
11
|
+
referencedDimensionNode,
|
|
11
12
|
node,
|
|
12
13
|
options,
|
|
13
14
|
onSubmit,
|
|
@@ -28,15 +29,15 @@ export default function LinkDimensionPopover({
|
|
|
28
29
|
};
|
|
29
30
|
}, [setPopoverAnchor]);
|
|
30
31
|
|
|
31
|
-
const columnDimension =
|
|
32
|
+
const columnDimension = referencedDimensionNode;
|
|
32
33
|
|
|
33
34
|
const handleSubmit = async (
|
|
34
35
|
{ node, column, dimension },
|
|
35
36
|
{ setSubmitting, setStatus },
|
|
36
37
|
) => {
|
|
37
38
|
setSubmitting(false);
|
|
38
|
-
if (
|
|
39
|
-
await unlinkDimension(node, column,
|
|
39
|
+
if (referencedDimensionNode && dimension === 'Remove') {
|
|
40
|
+
await unlinkDimension(node, column, referencedDimensionNode, setStatus);
|
|
40
41
|
} else {
|
|
41
42
|
await linkDimension(node, column, dimension, setStatus);
|
|
42
43
|
}
|
|
@@ -93,7 +94,7 @@ export default function LinkDimensionPopover({
|
|
|
93
94
|
column: column.name,
|
|
94
95
|
node: node.name,
|
|
95
96
|
dimension: '',
|
|
96
|
-
currentDimension:
|
|
97
|
+
currentDimension: referencedDimensionNode,
|
|
97
98
|
}}
|
|
98
99
|
onSubmit={handleSubmit}
|
|
99
100
|
>
|
|
@@ -110,10 +111,10 @@ export default function LinkDimensionPopover({
|
|
|
110
111
|
placeholder="Select dimension to link"
|
|
111
112
|
className=""
|
|
112
113
|
defaultValue={
|
|
113
|
-
|
|
114
|
+
referencedDimensionNode
|
|
114
115
|
? {
|
|
115
|
-
value:
|
|
116
|
-
label:
|
|
116
|
+
value: referencedDimensionNode,
|
|
117
|
+
label: referencedDimensionNode,
|
|
117
118
|
}
|
|
118
119
|
: ''
|
|
119
120
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialization configuration field.
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { ErrorMessage, Field, useFormikContext } from 'formik';
|
|
6
|
+
import CodeMirror from '@uiw/react-codemirror';
|
|
7
|
+
import { langs } from '@uiw/codemirror-extensions-langs';
|
|
8
|
+
|
|
9
|
+
export const ConfigField = ({ djClient, value }) => {
|
|
10
|
+
const formik = useFormikContext();
|
|
11
|
+
const jsonExt = langs.json();
|
|
12
|
+
|
|
13
|
+
const updateFormik = val => {
|
|
14
|
+
formik.setFieldValue('spark_config', val);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div className="DescriptionInput">
|
|
19
|
+
<ErrorMessage name="spark_config" component="span" />
|
|
20
|
+
<label htmlFor="SparkConfig">Spark Config</label>
|
|
21
|
+
<Field
|
|
22
|
+
type="textarea"
|
|
23
|
+
style={{ display: 'none' }}
|
|
24
|
+
as="textarea"
|
|
25
|
+
name="spark_config"
|
|
26
|
+
id="SparkConfig"
|
|
27
|
+
/>
|
|
28
|
+
<div role="button" tabIndex={0} className="relative flex bg-[#282a36]">
|
|
29
|
+
<CodeMirror
|
|
30
|
+
id={'spark_config'}
|
|
31
|
+
name={'spark_config'}
|
|
32
|
+
extensions={[jsonExt]}
|
|
33
|
+
value={JSON.stringify(value, null, " ")}
|
|
34
|
+
options={{
|
|
35
|
+
theme: 'default',
|
|
36
|
+
lineNumbers: true,
|
|
37
|
+
}}
|
|
38
|
+
width="100%"
|
|
39
|
+
height="170px"
|
|
40
|
+
style={{
|
|
41
|
+
margin: '0 0 23px 0',
|
|
42
|
+
flex: 1,
|
|
43
|
+
fontSize: '150%',
|
|
44
|
+
textAlign: 'left',
|
|
45
|
+
}}
|
|
46
|
+
onChange={(value, viewUpdate) => {
|
|
47
|
+
updateFormik(value);
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
@@ -12,6 +12,8 @@ export default function NodeColumnTab({ node, djClient }) {
|
|
|
12
12
|
const [attributes, setAttributes] = useState([]);
|
|
13
13
|
const [dimensions, setDimensions] = useState([]);
|
|
14
14
|
const [columns, setColumns] = useState([]);
|
|
15
|
+
const [links, setLinks] = useState([]);
|
|
16
|
+
|
|
15
17
|
useEffect(() => {
|
|
16
18
|
const fetchData = async () => {
|
|
17
19
|
setColumns(await djClient.columns(node));
|
|
@@ -88,92 +90,103 @@ export default function NodeColumnTab({ node, djClient }) {
|
|
|
88
90
|
};
|
|
89
91
|
|
|
90
92
|
const columnList = columns => {
|
|
91
|
-
return columns.map(col =>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
aria-hidden="false"
|
|
107
|
-
>
|
|
108
|
-
{col.display_name}
|
|
109
|
-
</span>
|
|
110
|
-
</td>
|
|
111
|
-
<td>
|
|
112
|
-
<span
|
|
113
|
-
className={`node_type__${
|
|
114
|
-
node.type === 'cube' ? col.type : 'transform'
|
|
115
|
-
} badge node_type`}
|
|
93
|
+
return columns.map(col => {
|
|
94
|
+
const dimensionLinks = (links.length > 0 ? links : node?.dimension_links)
|
|
95
|
+
.map(link => [
|
|
96
|
+
link.dimension.name,
|
|
97
|
+
Object.entries(link.foreign_keys).filter(
|
|
98
|
+
entry => entry[0] === node.name + '.' + col.name,
|
|
99
|
+
),
|
|
100
|
+
])
|
|
101
|
+
.filter(keys => keys[1].length >= 1);
|
|
102
|
+
const referencedDimensionNode =
|
|
103
|
+
dimensionLinks.length > 0 ? dimensionLinks[0][0] : null;
|
|
104
|
+
return (
|
|
105
|
+
<tr key={col.name}>
|
|
106
|
+
<td
|
|
107
|
+
className="text-start"
|
|
116
108
|
role="columnheader"
|
|
117
|
-
aria-label="
|
|
109
|
+
aria-label="ColumnName"
|
|
118
110
|
aria-hidden="false"
|
|
119
111
|
>
|
|
120
|
-
{col.
|
|
121
|
-
</
|
|
122
|
-
</td>
|
|
123
|
-
{node.type !== 'cube' ? (
|
|
112
|
+
{col.name}
|
|
113
|
+
</td>
|
|
124
114
|
<td>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
115
|
+
<span
|
|
116
|
+
className=""
|
|
117
|
+
role="columnheader"
|
|
118
|
+
aria-label="ColumnDisplayName"
|
|
119
|
+
aria-hidden="false"
|
|
120
|
+
>
|
|
121
|
+
{col.display_name}
|
|
122
|
+
</span>
|
|
123
|
+
</td>
|
|
124
|
+
<td>
|
|
125
|
+
<span
|
|
126
|
+
className={`node_type__${
|
|
127
|
+
node.type === 'cube' ? col.type : 'transform'
|
|
128
|
+
} badge node_type`}
|
|
129
|
+
role="columnheader"
|
|
130
|
+
aria-label="ColumnType"
|
|
131
|
+
aria-hidden="false"
|
|
132
|
+
>
|
|
133
|
+
{col.type}
|
|
134
|
+
</span>
|
|
144
135
|
</td>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
136
|
+
{node.type !== 'cube' ? (
|
|
137
|
+
<td>
|
|
138
|
+
{referencedDimensionNode !== null ? (
|
|
139
|
+
<a href={`/nodes/${referencedDimensionNode}`}>
|
|
140
|
+
{referencedDimensionNode}
|
|
141
|
+
</a>
|
|
142
|
+
) : (
|
|
143
|
+
''
|
|
144
|
+
)}
|
|
145
|
+
<LinkDimensionPopover
|
|
146
|
+
column={col}
|
|
147
|
+
referencedDimensionNode={referencedDimensionNode}
|
|
148
|
+
node={node}
|
|
149
|
+
options={dimensions}
|
|
150
|
+
onSubmit={async () => {
|
|
151
|
+
const res = await djClient.node(node.name);
|
|
152
|
+
setColumns(res.columns);
|
|
153
|
+
setLinks(res.dimension_links);
|
|
154
|
+
}}
|
|
155
|
+
/>
|
|
156
|
+
</td>
|
|
157
|
+
) : (
|
|
158
|
+
''
|
|
159
|
+
)}
|
|
160
|
+
{node.type !== 'cube' ? (
|
|
161
|
+
<td>
|
|
162
|
+
{showColumnAttributes(col)}
|
|
163
|
+
<EditColumnPopover
|
|
164
|
+
column={col}
|
|
165
|
+
node={node}
|
|
166
|
+
options={attributes}
|
|
167
|
+
onSubmit={async () => {
|
|
168
|
+
const res = await djClient.node(node.name);
|
|
169
|
+
setColumns(res.columns);
|
|
170
|
+
}}
|
|
171
|
+
/>
|
|
172
|
+
</td>
|
|
173
|
+
) : (
|
|
174
|
+
''
|
|
175
|
+
)}
|
|
149
176
|
<td>
|
|
150
|
-
{
|
|
151
|
-
<
|
|
177
|
+
{showColumnPartition(col)}
|
|
178
|
+
<PartitionColumnPopover
|
|
152
179
|
column={col}
|
|
153
180
|
node={node}
|
|
154
|
-
options={attributes}
|
|
155
181
|
onSubmit={async () => {
|
|
156
182
|
const res = await djClient.node(node.name);
|
|
157
183
|
setColumns(res.columns);
|
|
158
184
|
}}
|
|
159
185
|
/>
|
|
160
186
|
</td>
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
<td>
|
|
165
|
-
{showColumnPartition(col)}
|
|
166
|
-
<PartitionColumnPopover
|
|
167
|
-
column={col}
|
|
168
|
-
node={node}
|
|
169
|
-
onSubmit={async () => {
|
|
170
|
-
const res = await djClient.node(node.name);
|
|
171
|
-
setColumns(res.columns);
|
|
172
|
-
}}
|
|
173
|
-
/>
|
|
174
|
-
</td>
|
|
175
|
-
</tr>
|
|
176
|
-
));
|
|
187
|
+
</tr>
|
|
188
|
+
);
|
|
189
|
+
});
|
|
177
190
|
};
|
|
178
191
|
|
|
179
192
|
return (
|
|
@@ -15,6 +15,8 @@ const NodeLineage = djNode => {
|
|
|
15
15
|
col.attributes.some(attr => attr.attribute_type.name === 'primary_key'),
|
|
16
16
|
)
|
|
17
17
|
.map(col => col.name);
|
|
18
|
+
const dimensionLinkForeignKeys = node.dimension_links ? node.dimension_links
|
|
19
|
+
.flatMap(link => Object.keys(link.foreign_keys).map(key => key.split('.').slice(-1))) : [];
|
|
18
20
|
const column_names = node.columns
|
|
19
21
|
.map(col => {
|
|
20
22
|
return {
|
|
@@ -23,7 +25,7 @@ const NodeLineage = djNode => {
|
|
|
23
25
|
dimension: col.dimension !== null ? col.dimension.name : null,
|
|
24
26
|
order: primary_key.includes(col.name)
|
|
25
27
|
? -1
|
|
26
|
-
: col.
|
|
28
|
+
: dimensionLinkForeignKeys.includes(col.name)
|
|
27
29
|
? 0
|
|
28
30
|
: 1,
|
|
29
31
|
};
|
|
@@ -49,27 +51,29 @@ const NodeLineage = djNode => {
|
|
|
49
51
|
};
|
|
50
52
|
|
|
51
53
|
const dimensionEdges = node => {
|
|
52
|
-
return node.
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
54
|
+
return node.dimension_links === undefined ? [] : node.dimension_links
|
|
55
|
+
.flatMap(link => {
|
|
56
|
+
return Object.keys(link.foreign_keys).map(fk => {
|
|
57
|
+
return {
|
|
58
|
+
id: link.dimension.name + '->' + node.name + '=' + link.foreign_keys[fk] + '->' + fk,
|
|
59
|
+
source: link.dimension.name,
|
|
60
|
+
sourceHandle: link.foreign_keys[fk],
|
|
61
|
+
target: node.name,
|
|
62
|
+
targetHandle: fk,
|
|
63
|
+
draggable: true,
|
|
64
|
+
markerStart: {
|
|
65
|
+
type: MarkerType.Arrow,
|
|
66
|
+
width: 20,
|
|
67
|
+
height: 20,
|
|
68
|
+
color: '#b0b9c2',
|
|
69
|
+
},
|
|
70
|
+
style: {
|
|
71
|
+
strokeWidth: 3,
|
|
72
|
+
stroke: '#b0b9c2',
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
)
|
|
73
77
|
});
|
|
74
78
|
};
|
|
75
79
|
|
|
@@ -134,7 +134,8 @@ export default function NodeMaterializationTab({ node, djClient }) {
|
|
|
134
134
|
<div className="table-vertical">
|
|
135
135
|
<div>
|
|
136
136
|
<h2>Materializations</h2>
|
|
137
|
-
|
|
137
|
+
{node ?
|
|
138
|
+
<AddMaterializationPopover node={node} /> : <></>}
|
|
138
139
|
{materializations.length > 0 ? (
|
|
139
140
|
<table
|
|
140
141
|
className="card-inner-table table"
|
|
@@ -17,6 +17,9 @@ describe('<AddMaterializationPopover />', () => {
|
|
|
17
17
|
const onSubmitMock = jest.fn();
|
|
18
18
|
mockDjClient.DataJunctionAPI.materialize.mockReturnValue({
|
|
19
19
|
status: 201,
|
|
20
|
+
json: {
|
|
21
|
+
message: 'Saved!',
|
|
22
|
+
},
|
|
20
23
|
});
|
|
21
24
|
mockDjClient.DataJunctionAPI.materializationInfo.mockReturnValue({
|
|
22
25
|
status: 200,
|
|
@@ -42,6 +42,7 @@ describe('<LinkDimensionPopover />', () => {
|
|
|
42
42
|
<DJClientContext.Provider value={mockDjClient}>
|
|
43
43
|
<LinkDimensionPopover
|
|
44
44
|
column={column}
|
|
45
|
+
referencedDimensionNode={'default.dimension1'}
|
|
45
46
|
node={node}
|
|
46
47
|
options={options}
|
|
47
48
|
onSubmit={onSubmitMock}
|
|
@@ -94,7 +95,6 @@ describe('<LinkDimensionPopover />', () => {
|
|
|
94
95
|
};
|
|
95
96
|
const node = { name: 'default.node1' };
|
|
96
97
|
const options = [
|
|
97
|
-
{ value: 'Remove', label: '[Remove dimension link]' },
|
|
98
98
|
{ value: 'default.dimension1', label: 'Dimension 1' },
|
|
99
99
|
{ value: 'default.dimension2', label: 'Dimension 2' },
|
|
100
100
|
];
|
|
@@ -117,6 +117,7 @@ describe('<LinkDimensionPopover />', () => {
|
|
|
117
117
|
<DJClientContext.Provider value={mockDjClient}>
|
|
118
118
|
<LinkDimensionPopover
|
|
119
119
|
column={column}
|
|
120
|
+
referencedDimensionNode={'default.dimension1'}
|
|
120
121
|
node={node}
|
|
121
122
|
options={options}
|
|
122
123
|
onSubmit={onSubmitMock}
|
|
@@ -148,7 +149,7 @@ describe('<LinkDimensionPopover />', () => {
|
|
|
148
149
|
|
|
149
150
|
// Click on the 'Remove' option and save
|
|
150
151
|
fireEvent.keyDown(linkDimension.firstChild, { key: 'ArrowDown' });
|
|
151
|
-
fireEvent.click(screen.getByText('[Remove
|
|
152
|
+
fireEvent.click(screen.getByText('[Remove Dimension]'));
|
|
152
153
|
fireEvent.click(getByText('Save'));
|
|
153
154
|
getByText('Save').click();
|
|
154
155
|
|
|
@@ -98,6 +98,10 @@ describe('<NodeColumnTab />', () => {
|
|
|
98
98
|
'default.contractor.contractor_id = default.repair_orders.contractor_id',
|
|
99
99
|
join_cardinality: 'one_to_one',
|
|
100
100
|
role: 'contractor',
|
|
101
|
+
foreign_keys: {
|
|
102
|
+
'default.repair_orders.contractor_id':
|
|
103
|
+
'default.contractor.contractor_id',
|
|
104
|
+
},
|
|
101
105
|
},
|
|
102
106
|
],
|
|
103
107
|
};
|
|
@@ -73,6 +73,7 @@ describe('<NodeLineage />', () => {
|
|
|
73
73
|
parents: [],
|
|
74
74
|
created_at: '2023-08-21T16:48:52.970554+00:00',
|
|
75
75
|
tags: [],
|
|
76
|
+
dimension_links: [],
|
|
76
77
|
},
|
|
77
78
|
{
|
|
78
79
|
namespace: 'default',
|
|
@@ -98,6 +99,7 @@ describe('<NodeLineage />', () => {
|
|
|
98
99
|
query:
|
|
99
100
|
'\n SELECT\n dateint,\n month,\n year,\n day\n FROM default.date\n ',
|
|
100
101
|
availability: null,
|
|
102
|
+
dimension_links: [],
|
|
101
103
|
columns: [
|
|
102
104
|
{
|
|
103
105
|
name: 'dateint',
|
|
@@ -165,6 +167,7 @@ describe('<NodeLineage />', () => {
|
|
|
165
167
|
query:
|
|
166
168
|
'\n SELECT\n hard_hat_id,\n last_name,\n first_name,\n title,\n birth_date,\n hire_date,\n address,\n city,\n state,\n postal_code,\n country,\n manager,\n contractor_id\n FROM default.hard_hats\n ',
|
|
167
169
|
availability: null,
|
|
170
|
+
dimension_links: [],
|
|
168
171
|
columns: [
|
|
169
172
|
{
|
|
170
173
|
name: 'hard_hat_id',
|
|
@@ -292,6 +295,7 @@ describe('<NodeLineage />', () => {
|
|
|
292
295
|
query:
|
|
293
296
|
'SELECT avg(price) default_DOT_avg_repair_price \n FROM default.repair_order_details\n\n',
|
|
294
297
|
availability: null,
|
|
298
|
+
dimension_links: [],
|
|
295
299
|
columns: [
|
|
296
300
|
{
|
|
297
301
|
name: 'default_DOT_avg_repair_price',
|
|
@@ -24,11 +24,19 @@ export function Root() {
|
|
|
24
24
|
<div className="container d-flex align-items-center justify-content-between">
|
|
25
25
|
<div className="header">
|
|
26
26
|
<div className="logo">
|
|
27
|
-
<a
|
|
27
|
+
<a
|
|
28
|
+
href={'/'}
|
|
29
|
+
style={{
|
|
30
|
+
textTransform: 'none',
|
|
31
|
+
textDecoration: 'none',
|
|
32
|
+
color: '#000',
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
28
35
|
<h2>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
<DJLogo />
|
|
37
|
+
Data<b>Junction</b>
|
|
38
|
+
</h2>
|
|
39
|
+
</a>
|
|
32
40
|
</div>
|
|
33
41
|
<Search />
|
|
34
42
|
<div className="menu">
|
package/src/styles/index.css
CHANGED
|
@@ -241,7 +241,7 @@ table {
|
|
|
241
241
|
}
|
|
242
242
|
tr {
|
|
243
243
|
display: table-row;
|
|
244
|
-
vertical-align:
|
|
244
|
+
vertical-align: top;
|
|
245
245
|
border-color: inherit;
|
|
246
246
|
}
|
|
247
247
|
.card-table {
|
|
@@ -339,7 +339,7 @@ tr {
|
|
|
339
339
|
.table thead th,
|
|
340
340
|
td,
|
|
341
341
|
tbody th {
|
|
342
|
-
vertical-align:
|
|
342
|
+
vertical-align: top;
|
|
343
343
|
text-align: left;
|
|
344
344
|
}
|
|
345
345
|
.table [data-sort],
|
|
@@ -371,6 +371,7 @@ tbody th {
|
|
|
371
371
|
border-bottom: 0;
|
|
372
372
|
padding: 1rem;
|
|
373
373
|
max-width: 25rem;
|
|
374
|
+
vertical-align: top;
|
|
374
375
|
}
|
|
375
376
|
.card-inner-table td,
|
|
376
377
|
.card-inner-table th {
|