datajunction-ui 0.0.1-a46.dev3 → 0.0.1-a47

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.
@@ -19,216 +19,301 @@ HTMLCollection [
19
19
  `;
20
20
 
21
21
  exports[`<NodePage /> renders the NodeMaterialization tab with materializations correctly 1`] = `
22
- <table
23
- aria-hidden="false"
22
+ <div
24
23
  aria-label="Materializations"
25
- class="card-inner-table table"
24
+ class="table-vertical"
25
+ role="table"
26
26
  >
27
- <thead
28
- class="fs-7 fw-bold text-gray-400 border-bottom-0"
29
- >
30
- <tr>
31
- <th
32
- class="text-start"
27
+ <div>
28
+ <h2>
29
+ Materializations
30
+ </h2>
31
+ <button
32
+ aria-label="AddMaterialization"
33
+ class="edit_button"
34
+ tabindex="0"
35
+ >
36
+ <span
37
+ class="add_node"
33
38
  >
34
- Schedule
35
- </th>
36
- <th>
37
- Job Type
38
- </th>
39
- <th>
40
- Strategy
41
- </th>
42
- <th>
43
- Partitions
44
- </th>
45
- <th>
46
- Intended Output Tables
47
- </th>
48
- <th>
49
- URLs
50
- </th>
51
- </tr>
52
- </thead>
53
- <tbody>
54
- <tr>
55
- <td
56
- class="text-start node_name"
39
+ + Add Materialization
40
+ </span>
41
+ </button>
42
+ <div
43
+ class="fade modal-backdrop in"
44
+ style="display: none;"
45
+ />
46
+ <div
47
+ aria-label="client-code"
48
+ class="centerPopover"
49
+ role="dialog"
50
+ style="display: none; width: 50%;"
51
+ >
52
+ <form
53
+ action="#"
57
54
  >
55
+ <h2>
56
+ Configure Materialization
57
+ </h2>
58
+ <input
59
+ hidden=""
60
+ name="node"
61
+ readonly=""
62
+ value="default.repair_order_transform"
63
+ />
58
64
  <span
59
- class="badge cron"
65
+ data-testid="edit-partition"
60
66
  >
61
- 0 * * * *
67
+ <label
68
+ for="strategy"
69
+ >
70
+ Strategy
71
+ </label>
72
+ <select
73
+ name="strategy"
74
+ >
75
+ <option
76
+ value="full"
77
+ >
78
+ Full
79
+ </option>
80
+ <option
81
+ value="incremental_time"
82
+ >
83
+ Incremental Time
84
+ </option>
85
+ </select>
62
86
  </span>
63
- <div
64
- class="cron-description"
87
+ <br />
88
+ <br />
89
+ <label
90
+ for="schedule"
65
91
  >
66
- Every hour
67
-
68
- </div>
69
- </td>
70
- <td>
71
- SPARKSQL
72
- </td>
73
- <td />
74
- <td />
75
- <td>
92
+ Schedule
93
+ </label>
94
+ <input
95
+ default=""
96
+ id="schedule"
97
+ name="schedule"
98
+ placeholder="Cron"
99
+ type="text"
100
+ value="@daily"
101
+ />
102
+ <br />
103
+ <br />
76
104
  <div
77
- class="table__full"
105
+ class="DescriptionInput"
78
106
  >
79
- <div
80
- class="table__header"
107
+ <label
108
+ for="Config"
81
109
  >
82
- <svg
83
- class="bi bi-table"
84
- fill="currentColor"
85
- height="16"
86
- viewBox="0 0 16 16"
87
- width="16"
88
- xmlns="http://www.w3.org/2000/svg"
89
- >
90
- <path
91
- 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"
92
- />
93
- </svg>
94
-
95
- <span
96
- class="entity-info"
97
- >
98
- common.a
99
- </span>
100
- </div>
101
- <div
102
- class="table__body upstream_tables"
110
+ Lookback Window
111
+ </label>
112
+ <input
113
+ default=""
114
+ id="lookback_window"
115
+ name="lookback_window"
116
+ placeholder="1 DAY"
117
+ type="text"
118
+ value="1 DAY"
103
119
  />
104
120
  </div>
121
+ <br />
105
122
  <div
106
- class="table__full"
123
+ class="DescriptionInput"
107
124
  >
108
- <div
109
- class="table__header"
110
- >
111
- <svg
112
- class="bi bi-table"
113
- fill="currentColor"
114
- height="16"
115
- viewBox="0 0 16 16"
116
- width="16"
117
- xmlns="http://www.w3.org/2000/svg"
125
+ <details>
126
+ <summary>
127
+ <label
128
+ for="SparkConfig"
129
+ style="display: inline-block;"
130
+ >
131
+ Spark Config
132
+ </label>
133
+ </summary>
134
+ <textarea
135
+ id="SparkConfig"
136
+ name="spark_config"
137
+ style="display: none;"
138
+ type="textarea"
118
139
  >
119
- <path
120
- 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"
121
- />
122
- </svg>
123
-
124
- <span
125
- class="entity-info"
140
+ [object Object]
141
+ </textarea>
142
+ <div
143
+ class="relative flex bg-[#282a36]"
144
+ role="button"
145
+ tabindex="0"
126
146
  >
127
- common.b
128
- </span>
129
- </div>
130
- <div
131
- class="table__body upstream_tables"
132
- />
147
+ <div
148
+ class="cm-theme-light"
149
+ id="spark_config"
150
+ name="spark_config"
151
+ options="[object Object]"
152
+ style="margin: 0px 0px 23px 0px; flex: 1; font-size: 150%; text-align: left;"
153
+ >
154
+ <div
155
+ class="cm-editor ͼ1 ͼ2 ͼ4 ͼ1g ͼ15"
156
+ >
157
+ <div
158
+ aria-live="polite"
159
+ style="position: absolute; top: -10000px;"
160
+ />
161
+ <div
162
+ class="cm-scroller"
163
+ tabindex="-1"
164
+ >
165
+ <div
166
+ aria-hidden="true"
167
+ class="cm-gutters"
168
+ style="min-height: 56px; position: sticky;"
169
+ >
170
+ <div
171
+ class="cm-gutter cm-lineNumbers"
172
+ >
173
+ <div
174
+ class="cm-gutterElement"
175
+ style="height: 0px; visibility: hidden; pointer-events: none;"
176
+ >
177
+ 9
178
+ </div>
179
+ <div
180
+ class="cm-gutterElement cm-activeLineGutter"
181
+ style="height: 14px;"
182
+ >
183
+ 1
184
+ </div>
185
+ <div
186
+ class="cm-gutterElement"
187
+ style="height: 14px;"
188
+ >
189
+ 2
190
+ </div>
191
+ <div
192
+ class="cm-gutterElement"
193
+ style="height: 14px;"
194
+ >
195
+ 3
196
+ </div>
197
+ <div
198
+ class="cm-gutterElement"
199
+ style="height: 14px;"
200
+ >
201
+ 4
202
+ </div>
203
+ </div>
204
+ <div
205
+ class="cm-gutter cm-foldGutter"
206
+ >
207
+ <div
208
+ class="cm-gutterElement"
209
+ style="height: 0px; visibility: hidden; pointer-events: none;"
210
+ >
211
+ <span
212
+ title="Unfold line"
213
+ >
214
+
215
+ </span>
216
+ </div>
217
+ <div
218
+ class="cm-gutterElement cm-activeLineGutter"
219
+ style="height: 14px;"
220
+ >
221
+ <span
222
+ title="Fold line"
223
+ >
224
+
225
+ </span>
226
+ </div>
227
+ </div>
228
+ </div>
229
+ <div
230
+ aria-autocomplete="list"
231
+ aria-multiline="true"
232
+ autocapitalize="off"
233
+ autocorrect="off"
234
+ class="cm-content"
235
+ contenteditable="true"
236
+ data-language="json"
237
+ role="textbox"
238
+ spellcheck="false"
239
+ style="tab-size: 4"
240
+ translate="no"
241
+ >
242
+ <div
243
+ class="cm-activeLine cm-line"
244
+ >
245
+ {
246
+ </div>
247
+ <div
248
+ class="cm-line"
249
+ >
250
+ "spark.executor.memory":
251
+ <span
252
+ class="ͼe"
253
+ >
254
+ "16g"
255
+ </span>
256
+ ,
257
+ </div>
258
+ <div
259
+ class="cm-line"
260
+ >
261
+ "spark.memory.fraction":
262
+ <span
263
+ class="ͼe"
264
+ >
265
+ "0.3"
266
+ </span>
267
+ </div>
268
+ <div
269
+ class="cm-line"
270
+ >
271
+ }
272
+ </div>
273
+ </div>
274
+ <div
275
+ aria-hidden="true"
276
+ class="cm-selectionLayer"
277
+ />
278
+ <div
279
+ aria-hidden="true"
280
+ class="cm-cursorLayer"
281
+ style="animation-duration: 1200ms;"
282
+ />
283
+ </div>
284
+ </div>
285
+ </div>
286
+ </div>
287
+ </details>
288
+
133
289
  </div>
134
- </td>
135
- <td>
136
- <a
137
- href="http://fake.url/job"
138
- >
139
- [
140
- 1
141
- ]
142
- </a>
143
- </td>
144
- <td>
145
290
  <button
146
- aria-label="code-button"
147
- class="code-button"
148
- height="45px"
149
- tabindex="0"
291
+ aria-hidden="false"
292
+ aria-label="SaveEditColumn"
293
+ class="add_node"
294
+ type="submit"
150
295
  >
151
- <svg
152
- fill="none"
153
- height="45px"
154
- viewBox="0 0 64 64"
155
- width="45px"
156
- xmlns="http://www.w3.org/2000/svg"
157
- >
158
- <g
159
- id="SVGRepo_bgCarrier"
160
- stroke-width="0"
161
- />
162
- <g
163
- id="SVGRepo_tracerCarrier"
164
- stroke-linecap="round"
165
- stroke-linejoin="round"
166
- />
167
- <g
168
- id="SVGRepo_iconCarrier"
169
- >
170
- <path
171
- 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"
172
- fill="url(#a)"
173
- />
174
- <path
175
- 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"
176
- fill="url(#b)"
177
- />
178
- <defs>
179
- <lineargradient
180
- gradientUnits="userSpaceOnUse"
181
- id="a"
182
- x1="19.075"
183
- x2="34.898"
184
- y1="18.782"
185
- y2="34.658"
186
- >
187
- <stop
188
- stop-color="#387EB8"
189
- />
190
- <stop
191
- offset="1"
192
- stop-color="#366994"
193
- />
194
- </lineargradient>
195
- <lineargradient
196
- gradientUnits="userSpaceOnUse"
197
- id="b"
198
- x1="28.809"
199
- x2="45.803"
200
- y1="28.882"
201
- y2="45.163"
202
- >
203
- <stop
204
- stop-color="#FFE052"
205
- />
206
- <stop
207
- offset="1"
208
- stop-color="#FFC331"
209
- />
210
- </lineargradient>
211
- </defs>
212
- </g>
213
- </svg>
296
+ Save
214
297
  </button>
215
- <div
216
- aria-label="client-code"
217
- id="node-create-code"
218
- role="dialog"
219
- style="display: none;"
220
- >
221
- <pre
222
- style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(1, 22, 39); color: rgb(214, 222, 235);"
223
- >
224
- <code
225
- class="language-python"
226
- style="white-space: pre;"
227
- />
228
- </pre>
229
- </div>
230
- </td>
231
- </tr>
232
- </tbody>
233
- </table>
298
+ </form>
299
+ </div>
300
+ <div
301
+ class="message alert"
302
+ style="margin-top: 10px;"
303
+ >
304
+ No materialization workflows configured for this node.
305
+ </div>
306
+ </div>
307
+ <div>
308
+ <h2>
309
+ Materialized Datasets
310
+ </h2>
311
+ <div
312
+ class="message alert"
313
+ style="margin-top: 10px;"
314
+ >
315
+ No materialized datasets available for this node.
316
+ </div>
317
+ </div>
318
+ </div>
234
319
  `;
@@ -12,7 +12,7 @@ export const DataJunctionAPI = {
12
12
  },
13
13
 
14
14
  logout: async function () {
15
- await await fetch(`${DJ_URL}/logout/`, {
15
+ return await fetch(`${DJ_URL}/logout/`, {
16
16
  credentials: 'include',
17
17
  method: 'POST',
18
18
  });
@@ -388,19 +388,7 @@ export const DataJunctionAPI = {
388
388
  })
389
389
  ).json();
390
390
 
391
- return await Promise.all(
392
- data.map(async materialization => {
393
- materialization.clientCode = await (
394
- await fetch(
395
- `${DJ_URL}/datajunction-clients/python/add_materialization/${node}/${materialization.name}`,
396
- {
397
- credentials: 'include',
398
- },
399
- )
400
- ).json();
401
- return materialization;
402
- }),
403
- );
391
+ return data;
404
392
  },
405
393
 
406
394
  columns: async function (node) {
@@ -804,13 +792,7 @@ export const DataJunctionAPI = {
804
792
  );
805
793
  return { status: response.status, json: await response.json() };
806
794
  },
807
- runBackfill: async function (
808
- nodeName,
809
- materializationName,
810
- partitionColumn,
811
- from,
812
- to,
813
- ) {
795
+ runBackfill: async function (nodeName, materializationName, partitionValues) {
814
796
  const response = await fetch(
815
797
  `${DJ_URL}/nodes/${nodeName}/materializations/${materializationName}/backfill`,
816
798
  {
@@ -818,10 +800,29 @@ export const DataJunctionAPI = {
818
800
  headers: {
819
801
  'Content-Type': 'application/json',
820
802
  },
821
- body: JSON.stringify({
822
- column_name: partitionColumn,
823
- range: [from, to],
824
- }),
803
+ body: JSON.stringify(
804
+ partitionValues.map(partitionValue => {
805
+ return {
806
+ column_name: partitionValue.columnName,
807
+ range: partitionValue.range,
808
+ values: partitionValue.values,
809
+ };
810
+ }),
811
+ ),
812
+ credentials: 'include',
813
+ },
814
+ );
815
+ return { status: response.status, json: await response.json() };
816
+ },
817
+ deleteMaterialization: async function (nodeName, materializationName) {
818
+ console.log('deleting materialization', nodeName, materializationName);
819
+ const response = await fetch(
820
+ `${DJ_URL}/nodes/${nodeName}/materializations?materialization_name=${materializationName}`,
821
+ {
822
+ method: 'DELETE',
823
+ headers: {
824
+ 'Content-Type': 'application/json',
825
+ },
825
826
  credentials: 'include',
826
827
  },
827
828
  );
@@ -457,8 +457,8 @@ describe('DataJunctionAPI', () => {
457
457
  it('calls materializations correctly', async () => {
458
458
  const nodeName = 'default.sample_node';
459
459
  const mockMaterializations = [
460
- { name: 'materialization1', clientCode: 'from dj import DJClient' },
461
- { name: 'materialization2', clientCode: 'from dj import DJClient' },
460
+ { name: 'materialization1' },
461
+ { name: 'materialization2' },
462
462
  ];
463
463
 
464
464
  // Mock the first fetch call to return the list of materializations
@@ -481,14 +481,6 @@ describe('DataJunctionAPI', () => {
481
481
  },
482
482
  );
483
483
 
484
- // Check the subsequent fetch calls for clientCode
485
- mockMaterializations.forEach(mat => {
486
- expect(fetch).toHaveBeenCalledWith(
487
- `${DJ_URL}/datajunction-clients/python/add_materialization/${nodeName}/${mat.name}`,
488
- { credentials: 'include' },
489
- );
490
- });
491
-
492
484
  // Ensure the result contains the clientCode for each materialization
493
485
  expect(result).toEqual(mockMaterializations);
494
486
  });
@@ -981,13 +973,12 @@ describe('DataJunctionAPI', () => {
981
973
 
982
974
  it('calls runBackfill correctly', async () => {
983
975
  fetch.mockResponseOnce(JSON.stringify({}));
984
- await DataJunctionAPI.runBackfill(
985
- 'default.hard_hat',
986
- 'spark',
987
- 'hire_date',
988
- '20230101',
989
- '20230202',
990
- );
976
+ await DataJunctionAPI.runBackfill('default.hard_hat', 'spark', [
977
+ {
978
+ columnName: 'hire_date',
979
+ range: ['20230101', '20230202'],
980
+ },
981
+ ]);
991
982
  expect(fetch).toHaveBeenCalledWith(
992
983
  `${DJ_URL}/nodes/default.hard_hat/materializations/spark/backfill`,
993
984
  {
@@ -995,12 +986,37 @@ describe('DataJunctionAPI', () => {
995
986
  headers: {
996
987
  'Content-Type': 'application/json',
997
988
  },
998
- body: JSON.stringify({
999
- column_name: 'hire_date',
1000
- range: ['20230101', '20230202'],
1001
- }),
989
+ body: JSON.stringify([
990
+ {
991
+ column_name: 'hire_date',
992
+ range: ['20230101', '20230202'],
993
+ },
994
+ ]),
1002
995
  method: 'POST',
1003
996
  },
1004
997
  );
1005
998
  });
999
+
1000
+ it('calls materializationInfo correctly', async () => {
1001
+ fetch.mockResponseOnce(JSON.stringify({}));
1002
+ await DataJunctionAPI.materializationInfo();
1003
+ expect(fetch).toHaveBeenCalledWith(`${DJ_URL}/materialization/info`, {
1004
+ credentials: 'include',
1005
+ });
1006
+ });
1007
+
1008
+ it('calls revalidate correctly', async () => {
1009
+ fetch.mockResponseOnce(JSON.stringify({}));
1010
+ await DataJunctionAPI.revalidate('default.hard_hat');
1011
+ expect(fetch).toHaveBeenCalledWith(
1012
+ `${DJ_URL}/nodes/default.hard_hat/validate`,
1013
+ {
1014
+ credentials: 'include',
1015
+ method: 'POST',
1016
+ headers: {
1017
+ 'Content-Type': 'application/json',
1018
+ },
1019
+ },
1020
+ );
1021
+ });
1006
1022
  });