datajunction-ui 0.0.1-a1

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.
Files changed (154) hide show
  1. package/.babel-plugin-macrosrc.js +5 -0
  2. package/.env +3 -0
  3. package/.eslintrc.js +20 -0
  4. package/.gitattributes +201 -0
  5. package/.husky/pre-commit +6 -0
  6. package/.nvmrc +1 -0
  7. package/.prettierignore +6 -0
  8. package/.prettierrc +9 -0
  9. package/.stylelintrc +7 -0
  10. package/LICENSE +22 -0
  11. package/Makefile +3 -0
  12. package/README.md +10 -0
  13. package/dj-logo.svg +10 -0
  14. package/internals/testing/loadable.mock.tsx +6 -0
  15. package/package.json +189 -0
  16. package/public/favicon.ico +0 -0
  17. package/public/index.html +26 -0
  18. package/public/manifest.json +15 -0
  19. package/public/robots.txt +3 -0
  20. package/src/__tests__/reportWebVitals.test.jsx +44 -0
  21. package/src/app/__tests__/__snapshots__/index.test.tsx.snap +9 -0
  22. package/src/app/__tests__/index.test.tsx +14 -0
  23. package/src/app/components/DeleteNode.jsx +55 -0
  24. package/src/app/components/ListGroupItem.jsx +24 -0
  25. package/src/app/components/NamespaceHeader.jsx +31 -0
  26. package/src/app/components/QueryInfo.jsx +77 -0
  27. package/src/app/components/Tab.jsx +25 -0
  28. package/src/app/components/ToggleSwitch.jsx +20 -0
  29. package/src/app/components/__tests__/DeleteNode.test.jsx +53 -0
  30. package/src/app/components/__tests__/ListGroupItem.test.tsx +16 -0
  31. package/src/app/components/__tests__/NamespaceHeader.test.jsx +14 -0
  32. package/src/app/components/__tests__/QueryInfo.test.jsx +55 -0
  33. package/src/app/components/__tests__/Tab.test.jsx +27 -0
  34. package/src/app/components/__tests__/ToggleSwitch.test.jsx +43 -0
  35. package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +29 -0
  36. package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +47 -0
  37. package/src/app/components/djgraph/Collapse.jsx +46 -0
  38. package/src/app/components/djgraph/DJNode.jsx +89 -0
  39. package/src/app/components/djgraph/DJNodeColumns.jsx +71 -0
  40. package/src/app/components/djgraph/DJNodeDimensions.jsx +75 -0
  41. package/src/app/components/djgraph/LayoutFlow.jsx +104 -0
  42. package/src/app/components/djgraph/__tests__/Collapse.test.jsx +51 -0
  43. package/src/app/components/djgraph/__tests__/DJNode.test.tsx +24 -0
  44. package/src/app/components/djgraph/__tests__/DJNodeColumns.test.jsx +83 -0
  45. package/src/app/components/djgraph/__tests__/DJNodeDimensions.test.jsx +118 -0
  46. package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +117 -0
  47. package/src/app/constants.js +2 -0
  48. package/src/app/icons/AlertIcon.jsx +32 -0
  49. package/src/app/icons/CollapsedIcon.jsx +15 -0
  50. package/src/app/icons/DJLogo.jsx +36 -0
  51. package/src/app/icons/DeleteIcon.jsx +21 -0
  52. package/src/app/icons/EditIcon.jsx +18 -0
  53. package/src/app/icons/ExpandedIcon.jsx +15 -0
  54. package/src/app/icons/HorizontalHierarchyIcon.jsx +15 -0
  55. package/src/app/icons/InvalidIcon.jsx +14 -0
  56. package/src/app/icons/LoadingIcon.jsx +14 -0
  57. package/src/app/icons/PythonIcon.jsx +52 -0
  58. package/src/app/icons/TableIcon.jsx +14 -0
  59. package/src/app/icons/ValidIcon.jsx +14 -0
  60. package/src/app/index.tsx +108 -0
  61. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +46 -0
  62. package/src/app/pages/AddEditNodePage/FullNameField.jsx +37 -0
  63. package/src/app/pages/AddEditNodePage/Loadable.jsx +16 -0
  64. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +89 -0
  65. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +103 -0
  66. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +132 -0
  67. package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +75 -0
  68. package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +31 -0
  69. package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
  70. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +54 -0
  71. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +3 -0
  72. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +3 -0
  73. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +180 -0
  74. package/src/app/pages/AddEditNodePage/index.jsx +396 -0
  75. package/src/app/pages/AddEditTagPage/Loadable.jsx +16 -0
  76. package/src/app/pages/AddEditTagPage/__tests__/AddEditTagPage.test.jsx +107 -0
  77. package/src/app/pages/AddEditTagPage/index.jsx +132 -0
  78. package/src/app/pages/LoginPage/LoginForm.jsx +124 -0
  79. package/src/app/pages/LoginPage/SignupForm.jsx +156 -0
  80. package/src/app/pages/LoginPage/__tests__/index.test.jsx +97 -0
  81. package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
  82. package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
  83. package/src/app/pages/LoginPage/index.jsx +17 -0
  84. package/src/app/pages/NamespacePage/AddNamespacePopover.jsx +85 -0
  85. package/src/app/pages/NamespacePage/Explorer.jsx +57 -0
  86. package/src/app/pages/NamespacePage/Loadable.jsx +16 -0
  87. package/src/app/pages/NamespacePage/__tests__/index.test.jsx +217 -0
  88. package/src/app/pages/NamespacePage/index.jsx +199 -0
  89. package/src/app/pages/NodePage/AddBackfillPopover.jsx +166 -0
  90. package/src/app/pages/NodePage/AddMaterializationPopover.jsx +161 -0
  91. package/src/app/pages/NodePage/ClientCodePopover.jsx +46 -0
  92. package/src/app/pages/NodePage/EditColumnPopover.jsx +116 -0
  93. package/src/app/pages/NodePage/LinkDimensionPopover.jsx +149 -0
  94. package/src/app/pages/NodePage/Loadable.jsx +16 -0
  95. package/src/app/pages/NodePage/NodeColumnTab.jsx +200 -0
  96. package/src/app/pages/NodePage/NodeGraphTab.jsx +112 -0
  97. package/src/app/pages/NodePage/NodeHistory.jsx +212 -0
  98. package/src/app/pages/NodePage/NodeInfoTab.jsx +212 -0
  99. package/src/app/pages/NodePage/NodeLineageTab.jsx +84 -0
  100. package/src/app/pages/NodePage/NodeMaterializationTab.jsx +233 -0
  101. package/src/app/pages/NodePage/NodeSQLTab.jsx +82 -0
  102. package/src/app/pages/NodePage/NodeStatus.jsx +28 -0
  103. package/src/app/pages/NodePage/NodesWithDimension.jsx +42 -0
  104. package/src/app/pages/NodePage/PartitionColumnPopover.jsx +153 -0
  105. package/src/app/pages/NodePage/__tests__/AddBackfillPopover.test.jsx +47 -0
  106. package/src/app/pages/NodePage/__tests__/ClientCodePopover.test.jsx +49 -0
  107. package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +148 -0
  108. package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +165 -0
  109. package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +591 -0
  110. package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +57 -0
  111. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +757 -0
  112. package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
  113. package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +403 -0
  114. package/src/app/pages/NodePage/index.jsx +210 -0
  115. package/src/app/pages/NotFoundPage/Loadable.tsx +14 -0
  116. package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
  117. package/src/app/pages/NotFoundPage/index.tsx +23 -0
  118. package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
  119. package/src/app/pages/RegisterTablePage/__tests__/RegisterTablePage.test.jsx +110 -0
  120. package/src/app/pages/RegisterTablePage/__tests__/__snapshots__/RegisterTablePage.test.jsx.snap +37 -0
  121. package/src/app/pages/RegisterTablePage/index.jsx +142 -0
  122. package/src/app/pages/Root/Loadable.tsx +14 -0
  123. package/src/app/pages/Root/__tests__/index.test.jsx +77 -0
  124. package/src/app/pages/Root/assets/dj-logo.png +0 -0
  125. package/src/app/pages/Root/index.tsx +70 -0
  126. package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
  127. package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
  128. package/src/app/pages/SQLBuilderPage/index.jsx +390 -0
  129. package/src/app/pages/TagPage/Loadable.jsx +16 -0
  130. package/src/app/pages/TagPage/__tests__/TagPage.test.jsx +70 -0
  131. package/src/app/pages/TagPage/index.jsx +79 -0
  132. package/src/app/providers/djclient.jsx +5 -0
  133. package/src/app/services/DJService.js +665 -0
  134. package/src/app/services/__tests__/DJService.test.jsx +804 -0
  135. package/src/index.tsx +48 -0
  136. package/src/mocks/mockNodes.jsx +1430 -0
  137. package/src/react-app-env.d.ts +4 -0
  138. package/src/reportWebVitals.ts +15 -0
  139. package/src/setupTests.ts +36 -0
  140. package/src/styles/dag.css +228 -0
  141. package/src/styles/index.css +1083 -0
  142. package/src/styles/loading.css +34 -0
  143. package/src/styles/login.css +81 -0
  144. package/src/styles/node-creation.scss +197 -0
  145. package/src/styles/styles.scss +44 -0
  146. package/src/styles/styles.scss.d.ts +9 -0
  147. package/src/utils/__tests__/__snapshots__/loadable.test.tsx.snap +17 -0
  148. package/src/utils/__tests__/loadable.test.tsx +53 -0
  149. package/src/utils/__tests__/request.test.ts +82 -0
  150. package/src/utils/form.jsx +23 -0
  151. package/src/utils/loadable.tsx +30 -0
  152. package/src/utils/request.ts +54 -0
  153. package/tsconfig.json +34 -0
  154. package/webpack.config.js +118 -0
@@ -0,0 +1,665 @@
1
+ import { MarkerType } from 'reactflow';
2
+
3
+ const DJ_URL = process.env.REACT_APP_DJ_URL
4
+ ? process.env.REACT_APP_DJ_URL
5
+ : 'http://localhost:8000';
6
+
7
+ export const DataJunctionAPI = {
8
+ whoami: async function () {
9
+ return await (
10
+ await fetch(`${DJ_URL}/whoami/`, { credentials: 'include' })
11
+ ).json();
12
+ },
13
+
14
+ logout: async function () {
15
+ await await fetch(`${DJ_URL}/logout/`, {
16
+ credentials: 'include',
17
+ method: 'POST',
18
+ });
19
+ },
20
+
21
+ catalogs: async function () {
22
+ return await (
23
+ await fetch(`${DJ_URL}/catalogs`, {
24
+ credentials: 'include',
25
+ })
26
+ ).json();
27
+ },
28
+
29
+ engines: async function () {
30
+ return await (
31
+ await fetch(`${DJ_URL}/engines`, {
32
+ credentials: 'include',
33
+ })
34
+ ).json();
35
+ },
36
+
37
+ node: async function (name) {
38
+ const data = await (
39
+ await fetch(`${DJ_URL}/nodes/${name}/`, {
40
+ credentials: 'include',
41
+ })
42
+ ).json();
43
+ if (data.message !== undefined) {
44
+ return data;
45
+ }
46
+ data.primary_key = data.columns
47
+ .filter(col =>
48
+ col.attributes.some(attr => attr.attribute_type.name === 'primary_key'),
49
+ )
50
+ .map(col => col.name);
51
+ return data;
52
+ },
53
+
54
+ nodes: async function (prefix) {
55
+ return await (
56
+ await fetch(`${DJ_URL}/nodes/?prefix=${prefix}`, {
57
+ credentials: 'include',
58
+ })
59
+ ).json();
60
+ },
61
+
62
+ createNode: async function (
63
+ nodeType,
64
+ name,
65
+ display_name,
66
+ description,
67
+ query,
68
+ mode,
69
+ namespace,
70
+ primary_key,
71
+ ) {
72
+ const response = await fetch(`${DJ_URL}/nodes/${nodeType}`, {
73
+ method: 'POST',
74
+ headers: {
75
+ 'Content-Type': 'application/json',
76
+ },
77
+ body: JSON.stringify({
78
+ name: name,
79
+ display_name: display_name,
80
+ description: description,
81
+ query: query,
82
+ mode: mode,
83
+ namespace: namespace,
84
+ primary_key: primary_key,
85
+ }),
86
+ credentials: 'include',
87
+ });
88
+ return { status: response.status, json: await response.json() };
89
+ },
90
+
91
+ patchNode: async function (
92
+ name,
93
+ display_name,
94
+ description,
95
+ query,
96
+ mode,
97
+ primary_key,
98
+ ) {
99
+ try {
100
+ const response = await fetch(`${DJ_URL}/nodes/${name}`, {
101
+ method: 'PATCH',
102
+ headers: {
103
+ 'Content-Type': 'application/json',
104
+ },
105
+ body: JSON.stringify({
106
+ display_name: display_name,
107
+ description: description,
108
+ query: query,
109
+ mode: mode,
110
+ primary_key: primary_key,
111
+ }),
112
+ credentials: 'include',
113
+ });
114
+ return { status: response.status, json: await response.json() };
115
+ } catch (error) {
116
+ return { status: 500, json: { message: 'Update failed' } };
117
+ }
118
+ },
119
+
120
+ registerTable: async function (catalog, schema, table) {
121
+ const response = await fetch(
122
+ `${DJ_URL}/register/table/${catalog}/${schema}/${table}`,
123
+ {
124
+ method: 'POST',
125
+ headers: {
126
+ 'Content-Type': 'application/json',
127
+ },
128
+ credentials: 'include',
129
+ },
130
+ );
131
+ return { status: response.status, json: await response.json() };
132
+ },
133
+
134
+ upstreams: async function (name) {
135
+ return await (
136
+ await fetch(`${DJ_URL}/nodes/${name}/upstream/`, {
137
+ credentials: 'include',
138
+ })
139
+ ).json();
140
+ },
141
+
142
+ downstreams: async function (name) {
143
+ return await (
144
+ await fetch(`${DJ_URL}/nodes/${name}/downstream/`, {
145
+ credentials: 'include',
146
+ })
147
+ ).json();
148
+ },
149
+
150
+ node_dag: async function (name) {
151
+ return await (
152
+ await fetch(`${DJ_URL}/nodes/${name}/dag/`, {
153
+ credentials: 'include',
154
+ })
155
+ ).json();
156
+ },
157
+
158
+ node_lineage: async function (name) {
159
+ return await (
160
+ await fetch(`${DJ_URL}/nodes/${name}/lineage/`, {
161
+ credentials: 'include',
162
+ })
163
+ ).json();
164
+ },
165
+
166
+ metric: async function (name) {
167
+ return await (
168
+ await fetch(`${DJ_URL}/metrics/${name}/`, {
169
+ credentials: 'include',
170
+ })
171
+ ).json();
172
+ },
173
+
174
+ clientCode: async function (name) {
175
+ return await (
176
+ await fetch(`${DJ_URL}/datajunction-clients/python/new_node/${name}`, {
177
+ credentials: 'include',
178
+ })
179
+ ).json();
180
+ },
181
+
182
+ cube: async function (name) {
183
+ return await (
184
+ await fetch(`${DJ_URL}/cubes/${name}/`, {
185
+ credentials: 'include',
186
+ })
187
+ ).json();
188
+ },
189
+
190
+ metrics: async function (name) {
191
+ return await (
192
+ await fetch(`${DJ_URL}/metrics/`, {
193
+ credentials: 'include',
194
+ })
195
+ ).json();
196
+ },
197
+
198
+ commonDimensions: async function (metrics) {
199
+ const metricsQuery = '?' + metrics.map(m => `metric=${m}`).join('&');
200
+ return await (
201
+ await fetch(`${DJ_URL}/metrics/common/dimensions/${metricsQuery}`, {
202
+ credentials: 'include',
203
+ })
204
+ ).json();
205
+ },
206
+
207
+ history: async function (type, name, offset, limit) {
208
+ return await (
209
+ await fetch(
210
+ `${DJ_URL}/history?node=${name}&offset=${offset ? offset : 0}&limit=${
211
+ limit ? limit : 100
212
+ }`,
213
+ {
214
+ credentials: 'include',
215
+ },
216
+ )
217
+ ).json();
218
+ },
219
+
220
+ revisions: async function (name) {
221
+ return await (
222
+ await fetch(`${DJ_URL}/nodes/${name}/revisions/`, {
223
+ credentials: 'include',
224
+ })
225
+ ).json();
226
+ },
227
+
228
+ namespace: async function (nmspce) {
229
+ return await (
230
+ await fetch(`${DJ_URL}/namespaces/${nmspce}/`, {
231
+ credentials: 'include',
232
+ })
233
+ ).json();
234
+ },
235
+
236
+ namespaces: async function () {
237
+ return await (
238
+ await fetch(`${DJ_URL}/namespaces/`, {
239
+ credentials: 'include',
240
+ })
241
+ ).json();
242
+ },
243
+
244
+ sql: async function (metric_name, selection) {
245
+ return await (
246
+ await fetch(
247
+ `${DJ_URL}/sql/${metric_name}?` + new URLSearchParams(selection),
248
+ {
249
+ credentials: 'include',
250
+ },
251
+ )
252
+ ).json();
253
+ },
254
+
255
+ nodesWithDimension: async function (name) {
256
+ return await (
257
+ await fetch(`${DJ_URL}/dimensions/${name}/nodes/`, {
258
+ credentials: 'include',
259
+ })
260
+ ).json();
261
+ },
262
+
263
+ materializations: async function (node) {
264
+ const data = await (
265
+ await fetch(`${DJ_URL}/nodes/${node}/materializations/`, {
266
+ credentials: 'include',
267
+ })
268
+ ).json();
269
+
270
+ return await Promise.all(
271
+ data.map(async materialization => {
272
+ materialization.clientCode = await (
273
+ await fetch(
274
+ `${DJ_URL}/datajunction-clients/python/add_materialization/${node}/${materialization.name}`,
275
+ {
276
+ credentials: 'include',
277
+ },
278
+ )
279
+ ).json();
280
+ return materialization;
281
+ }),
282
+ );
283
+ },
284
+
285
+ columns: async function (node) {
286
+ return await Promise.all(
287
+ node.columns.map(async col => {
288
+ if (col.dimension) {
289
+ col.clientCode = await (
290
+ await fetch(
291
+ `${DJ_URL}/datajunction-clients/python/link_dimension/${node.name}/${col.name}/${col.dimension?.name}`,
292
+ {
293
+ credentials: 'include',
294
+ },
295
+ )
296
+ ).json();
297
+ }
298
+ return col;
299
+ }),
300
+ );
301
+ },
302
+
303
+ sqls: async function (metricSelection, dimensionSelection, filters) {
304
+ const params = new URLSearchParams();
305
+ metricSelection.map(metric => params.append('metrics', metric));
306
+ dimensionSelection.map(dimension => params.append('dimensions', dimension));
307
+ params.append('filters', filters);
308
+ return await (
309
+ await fetch(`${DJ_URL}/sql/?${params}`, {
310
+ credentials: 'include',
311
+ })
312
+ ).json();
313
+ },
314
+
315
+ data: async function (metricSelection, dimensionSelection) {
316
+ const params = new URLSearchParams();
317
+ metricSelection.map(metric => params.append('metrics', metric));
318
+ dimensionSelection.map(dimension => params.append('dimensions', dimension));
319
+ return await (
320
+ await fetch(`${DJ_URL}/data/?` + params + '&limit=10000', {
321
+ credentials: 'include',
322
+ })
323
+ ).json();
324
+ },
325
+
326
+ stream: async function (metricSelection, dimensionSelection, filters) {
327
+ const params = new URLSearchParams();
328
+ metricSelection.map(metric => params.append('metrics', metric));
329
+ dimensionSelection.map(dimension => params.append('dimensions', dimension));
330
+ params.append('filters', filters);
331
+ return new EventSource(
332
+ `${DJ_URL}/stream/?${params}&limit=10000&async_=true`,
333
+ {
334
+ withCredentials: true,
335
+ },
336
+ );
337
+ },
338
+
339
+ lineage: async function (node) {},
340
+
341
+ compiledSql: async function (node) {
342
+ return await (
343
+ await fetch(`${DJ_URL}/sql/${node}/`, {
344
+ credentials: 'include',
345
+ })
346
+ ).json();
347
+ },
348
+
349
+ dag: async function (namespace = 'default') {
350
+ const edges = [];
351
+ const data = await (
352
+ await fetch(`${DJ_URL}/nodes/`, {
353
+ credentials: 'include',
354
+ })
355
+ ).json();
356
+
357
+ data.forEach(obj => {
358
+ obj.parents.forEach(parent => {
359
+ if (parent.name) {
360
+ edges.push({
361
+ id: obj.name + '-' + parent.name,
362
+ target: obj.name,
363
+ source: parent.name,
364
+ animated: true,
365
+ markerEnd: {
366
+ type: MarkerType.Arrow,
367
+ },
368
+ });
369
+ }
370
+ });
371
+
372
+ obj.columns.forEach(col => {
373
+ if (col.dimension) {
374
+ edges.push({
375
+ id: obj.name + '-' + col.dimension.name,
376
+ target: obj.name,
377
+ source: col.dimension.name,
378
+ draggable: true,
379
+ });
380
+ }
381
+ });
382
+ });
383
+ const namespaces = new Set(
384
+ data.flatMap(node => node.name.split('.').slice(0, -1)),
385
+ );
386
+ const namespaceNodes = Array.from(namespaces).map(namespace => {
387
+ return {
388
+ id: String(namespace),
389
+ type: 'DJNamespace',
390
+ data: {
391
+ label: String(namespace),
392
+ },
393
+ };
394
+ });
395
+
396
+ const nodes = data.map((node, index) => {
397
+ const primary_key = node.columns
398
+ .filter(col =>
399
+ col.attributes.some(
400
+ attr => attr.attribute_type.name === 'primary_key',
401
+ ),
402
+ )
403
+ .map(col => col.name);
404
+ const column_names = node.columns.map(col => {
405
+ return { name: col.name, type: col.type };
406
+ });
407
+ return {
408
+ id: String(node.name),
409
+ type: 'DJNode',
410
+ data: {
411
+ label:
412
+ node.table !== null
413
+ ? String(node.schema_ + '.' + node.table)
414
+ : String(node.name),
415
+ table: node.table,
416
+ name: String(node.name),
417
+ display_name: String(node.display_name),
418
+ type: node.type,
419
+ primary_key: primary_key,
420
+ column_names: column_names,
421
+ },
422
+ };
423
+ });
424
+
425
+ return { edges: edges, nodes: nodes, namespaces: namespaceNodes };
426
+ },
427
+ attributes: async function () {
428
+ return await (
429
+ await fetch(`${DJ_URL}/attributes`, {
430
+ credentials: 'include',
431
+ })
432
+ ).json();
433
+ },
434
+ setAttributes: async function (nodeName, columnName, attributes) {
435
+ const response = await fetch(
436
+ `${DJ_URL}/nodes/${nodeName}/columns/${columnName}/attributes`,
437
+ {
438
+ method: 'POST',
439
+ headers: {
440
+ 'Content-Type': 'application/json',
441
+ },
442
+ body: JSON.stringify(
443
+ attributes.map(attribute => {
444
+ return {
445
+ namespace: 'system',
446
+ name: attribute,
447
+ };
448
+ }),
449
+ ),
450
+ credentials: 'include',
451
+ },
452
+ );
453
+ return { status: response.status, json: await response.json() };
454
+ },
455
+ dimensions: async function () {
456
+ return await (
457
+ await fetch(`${DJ_URL}/dimensions`, {
458
+ credentials: 'include',
459
+ })
460
+ ).json();
461
+ },
462
+ linkDimension: async function (nodeName, columnName, dimensionName) {
463
+ const response = await fetch(
464
+ `${DJ_URL}/nodes/${nodeName}/columns/${columnName}?dimension=${dimensionName}`,
465
+ {
466
+ method: 'POST',
467
+ headers: {
468
+ 'Content-Type': 'application/json',
469
+ },
470
+ credentials: 'include',
471
+ },
472
+ );
473
+ return { status: response.status, json: await response.json() };
474
+ },
475
+ unlinkDimension: async function (nodeName, columnName, dimensionName) {
476
+ const response = await fetch(
477
+ `${DJ_URL}/nodes/${nodeName}/columns/${columnName}?dimension=${dimensionName}`,
478
+ {
479
+ method: 'DELETE',
480
+ headers: {
481
+ 'Content-Type': 'application/json',
482
+ },
483
+ credentials: 'include',
484
+ },
485
+ );
486
+ return { status: response.status, json: await response.json() };
487
+ },
488
+ deactivate: async function (nodeName) {
489
+ const response = await fetch(`${DJ_URL}/nodes/${nodeName}`, {
490
+ method: 'DELETE',
491
+ headers: {
492
+ 'Content-Type': 'application/json',
493
+ },
494
+ credentials: 'include',
495
+ });
496
+ return { status: response.status, json: await response.json() };
497
+ },
498
+ addNamespace: async function (namespace) {
499
+ const response = await fetch(`${DJ_URL}/namespaces/${namespace}`, {
500
+ method: 'POST',
501
+ headers: {
502
+ 'Content-Type': 'application/json',
503
+ },
504
+ credentials: 'include',
505
+ });
506
+ return { status: response.status, json: await response.json() };
507
+ },
508
+ listTags: async function () {
509
+ const response = await fetch(`${DJ_URL}/tags`, {
510
+ method: 'GET',
511
+ headers: {
512
+ 'Content-Type': 'application/json',
513
+ },
514
+ credentials: 'include',
515
+ });
516
+ return await response.json();
517
+ },
518
+ getTag: async function (tagName) {
519
+ const response = await fetch(`${DJ_URL}/tags/${tagName}`, {
520
+ method: 'GET',
521
+ headers: {
522
+ 'Content-Type': 'application/json',
523
+ },
524
+ credentials: 'include',
525
+ });
526
+ return await response.json();
527
+ },
528
+ listNodesForTag: async function (tagName) {
529
+ const response = await fetch(`${DJ_URL}/tags/${tagName}/nodes`, {
530
+ method: 'GET',
531
+ headers: {
532
+ 'Content-Type': 'application/json',
533
+ },
534
+ credentials: 'include',
535
+ });
536
+ return await response.json();
537
+ },
538
+ tagsNode: async function (nodeName, tagNames) {
539
+ const url = tagNames
540
+ .map(value => `tag_names=${encodeURIComponent(value)}`)
541
+ .join('&');
542
+ const response = await fetch(`${DJ_URL}/nodes/${nodeName}/tags?${url}`, {
543
+ method: 'POST',
544
+ headers: {
545
+ 'Content-Type': 'application/json',
546
+ },
547
+ credentials: 'include',
548
+ });
549
+ return { status: response.status, json: await response.json() };
550
+ },
551
+ addTag: async function (name, displayName, tagType, description) {
552
+ const response = await fetch(`${DJ_URL}/tags`, {
553
+ method: 'POST',
554
+ headers: {
555
+ 'Content-Type': 'application/json',
556
+ },
557
+ body: JSON.stringify({
558
+ name: name,
559
+ display_name: displayName,
560
+ tag_type: tagType,
561
+ description: description,
562
+ }),
563
+ credentials: 'include',
564
+ });
565
+ return { status: response.status, json: await response.json() };
566
+ },
567
+ editTag: async function (name, description, displayName) {
568
+ const updates = {};
569
+ if (description) {
570
+ updates.description = description;
571
+ }
572
+ if (displayName) {
573
+ updates.display_name = displayName;
574
+ }
575
+
576
+ const response = await fetch(`${DJ_URL}/tags/${name}`, {
577
+ method: 'PATCH',
578
+ headers: {
579
+ 'Content-Type': 'application/json',
580
+ },
581
+ body: JSON.stringify(updates),
582
+ credentials: 'include',
583
+ });
584
+ return { status: response.status, json: await response.json() };
585
+ },
586
+ setPartition: async function (
587
+ nodeName,
588
+ columnName,
589
+ partitionType,
590
+ format,
591
+ granularity,
592
+ ) {
593
+ const body = {
594
+ type_: partitionType,
595
+ };
596
+ if (format) {
597
+ body.format = format;
598
+ }
599
+ if (granularity) {
600
+ body.granularity = granularity;
601
+ }
602
+ const response = await fetch(
603
+ `${DJ_URL}/nodes/${nodeName}/columns/${columnName}/partition`,
604
+ {
605
+ method: 'POST',
606
+ headers: {
607
+ 'Content-Type': 'application/json',
608
+ },
609
+ body: JSON.stringify(body),
610
+ credentials: 'include',
611
+ },
612
+ );
613
+ return { status: response.status, json: await response.json() };
614
+ },
615
+ materialize: async function (
616
+ nodeName,
617
+ engineName,
618
+ engineVersion,
619
+ schedule,
620
+ config,
621
+ ) {
622
+ const response = await fetch(
623
+ `${DJ_URL}/nodes/${nodeName}/materialization`,
624
+ {
625
+ method: 'POST',
626
+ headers: {
627
+ 'Content-Type': 'application/json',
628
+ },
629
+ body: JSON.stringify({
630
+ engine: {
631
+ name: engineName,
632
+ version: engineVersion,
633
+ },
634
+ schedule: schedule,
635
+ config: JSON.parse(config),
636
+ }),
637
+ credentials: 'include',
638
+ },
639
+ );
640
+ return { status: response.status, json: await response.json() };
641
+ },
642
+ runBackfill: async function (
643
+ nodeName,
644
+ materializationName,
645
+ partitionColumn,
646
+ from,
647
+ to,
648
+ ) {
649
+ const response = await fetch(
650
+ `${DJ_URL}/nodes/${nodeName}/materializations/${materializationName}/backfill`,
651
+ {
652
+ method: 'POST',
653
+ headers: {
654
+ 'Content-Type': 'application/json',
655
+ },
656
+ body: JSON.stringify({
657
+ column_name: partitionColumn,
658
+ range: [from, to],
659
+ }),
660
+ credentials: 'include',
661
+ },
662
+ );
663
+ return { status: response.status, json: await response.json() };
664
+ },
665
+ };