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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datajunction-ui",
3
- "version": "0.0.1-a44.dev1",
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": 90,
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 = JSON.parse(values.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: 'Saved!' });
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
- {jobs?.map(job => (
108
- <option key={job.name} value={job.name}>
109
- {job.label}
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
- {options.strategies?.map(strategy => (
128
- <option value={strategy.name}>{strategy.label}</option>
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
- <div className="DescriptionInput">
158
- <ErrorMessage name="description" component="span" />
159
- <label htmlFor="Config">Config</label>
160
- <Field
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.dimension !== null
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.columns
53
- .filter(col => col.dimension)
54
- .map(col => {
55
- return {
56
- id: col.dimension.name + '->' + node.name + '.' + col.name,
57
- source: col.dimension.name,
58
- sourceHandle: col.dimension.name,
59
- target: node.name,
60
- targetHandle: node.name + '.' + col.name,
61
- draggable: true,
62
- markerStart: {
63
- type: MarkerType.Arrow,
64
- width: 20,
65
- height: 20,
66
- color: '#b0b9c2',
67
- },
68
- style: {
69
- strokeWidth: 3,
70
- stroke: '#b0b9c2',
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
- <AddMaterializationPopover node={node} />
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',
@@ -241,7 +241,7 @@ table {
241
241
  }
242
242
  tr {
243
243
  display: table-row;
244
- vertical-align: inherit;
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: middle;
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 {