datajunction-ui 0.0.1-a44.dev1 → 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/MaterializationConfigField.jsx +53 -0
- 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__/NodeGraphTab.test.jsx +4 -0
- 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"
|
|
@@ -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
|
+
};
|
|
@@ -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,
|
|
@@ -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',
|
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 {
|