datajunction-ui 0.0.1-rc.2 → 0.0.1-rc.20

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 (135) hide show
  1. package/.env +1 -0
  2. package/.prettierignore +3 -1
  3. package/dj-logo.svg +10 -0
  4. package/package.json +43 -13
  5. package/public/favicon.ico +0 -0
  6. package/src/__tests__/reportWebVitals.test.jsx +44 -0
  7. package/src/app/__tests__/__snapshots__/index.test.tsx.snap +5 -39
  8. package/src/app/components/DeleteNode.jsx +79 -0
  9. package/src/app/components/ListGroupItem.jsx +8 -1
  10. package/src/app/components/NamespaceHeader.jsx +4 -13
  11. package/src/app/components/QueryInfo.jsx +77 -0
  12. package/src/app/components/Tab.jsx +3 -2
  13. package/src/app/components/ToggleSwitch.jsx +20 -0
  14. package/src/app/components/__tests__/QueryInfo.test.jsx +55 -0
  15. package/src/app/components/__tests__/Tab.test.jsx +27 -0
  16. package/src/app/components/__tests__/ToggleSwitch.test.jsx +43 -0
  17. package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +3 -0
  18. package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +2 -18
  19. package/src/app/components/djgraph/Collapse.jsx +46 -0
  20. package/src/app/components/djgraph/DJNode.jsx +60 -82
  21. package/src/app/components/djgraph/DJNodeColumns.jsx +71 -0
  22. package/src/app/components/djgraph/DJNodeDimensions.jsx +75 -0
  23. package/src/app/components/djgraph/LayoutFlow.jsx +104 -0
  24. package/src/app/components/djgraph/__tests__/Collapse.test.jsx +51 -0
  25. package/src/app/components/djgraph/__tests__/DJNodeColumns.test.jsx +83 -0
  26. package/src/app/components/djgraph/__tests__/DJNodeDimensions.test.jsx +118 -0
  27. package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +84 -40
  28. package/src/app/constants.js +2 -0
  29. package/src/app/icons/AlertIcon.jsx +32 -0
  30. package/src/app/icons/CollapsedIcon.jsx +15 -0
  31. package/src/app/icons/DJLogo.jsx +36 -0
  32. package/src/app/icons/DeleteIcon.jsx +21 -0
  33. package/src/app/icons/EditIcon.jsx +18 -0
  34. package/src/app/icons/ExpandedIcon.jsx +15 -0
  35. package/src/app/icons/HorizontalHierarchyIcon.jsx +15 -0
  36. package/src/app/icons/InvalidIcon.jsx +14 -0
  37. package/src/app/icons/PythonIcon.jsx +52 -0
  38. package/src/app/icons/TableIcon.jsx +14 -0
  39. package/src/app/icons/ValidIcon.jsx +14 -0
  40. package/src/app/index.tsx +79 -26
  41. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +46 -0
  42. package/src/app/pages/AddEditNodePage/FullNameField.jsx +37 -0
  43. package/src/app/pages/AddEditNodePage/Loadable.jsx +16 -0
  44. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +89 -0
  45. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +77 -0
  46. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +93 -0
  47. package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +75 -0
  48. package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +31 -0
  49. package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
  50. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +53 -0
  51. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +53 -0
  52. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +3 -0
  53. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +178 -0
  54. package/src/app/pages/AddEditNodePage/index.jsx +357 -0
  55. package/src/app/pages/LoginPage/__tests__/index.test.jsx +70 -0
  56. package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
  57. package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
  58. package/src/app/pages/LoginPage/index.jsx +90 -0
  59. package/src/app/pages/NamespacePage/Explorer.jsx +57 -0
  60. package/src/app/pages/NamespacePage/Loadable.jsx +9 -7
  61. package/src/app/pages/NamespacePage/__tests__/index.test.jsx +95 -0
  62. package/src/app/pages/NamespacePage/index.jsx +131 -31
  63. package/src/app/pages/NodePage/ClientCodePopover.jsx +32 -0
  64. package/src/app/pages/NodePage/EditColumnPopover.jsx +102 -0
  65. package/src/app/pages/NodePage/LinkDimensionPopover.jsx +135 -0
  66. package/src/app/pages/NodePage/Loadable.jsx +9 -7
  67. package/src/app/pages/NodePage/NodeColumnTab.jsx +106 -27
  68. package/src/app/pages/NodePage/NodeGraphTab.jsx +94 -148
  69. package/src/app/pages/NodePage/NodeHistory.jsx +212 -0
  70. package/src/app/pages/NodePage/NodeInfoTab.jsx +166 -51
  71. package/src/app/pages/NodePage/NodeLineageTab.jsx +84 -0
  72. package/src/app/pages/NodePage/NodeMaterializationTab.jsx +174 -0
  73. package/src/app/pages/NodePage/NodeSQLTab.jsx +82 -0
  74. package/src/app/pages/NodePage/NodeStatus.jsx +14 -20
  75. package/src/app/pages/NodePage/NodesWithDimension.jsx +42 -0
  76. package/src/app/pages/NodePage/__tests__/ClientCodePopover.test.jsx +49 -0
  77. package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +148 -0
  78. package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +165 -0
  79. package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +591 -0
  80. package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +57 -0
  81. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +725 -0
  82. package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
  83. package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +402 -0
  84. package/src/app/pages/NodePage/index.jsx +151 -41
  85. package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
  86. package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
  87. package/src/app/pages/RegisterTablePage/index.jsx +163 -0
  88. package/src/app/pages/Root/__tests__/index.test.jsx +77 -0
  89. package/src/app/pages/Root/index.tsx +32 -4
  90. package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
  91. package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
  92. package/src/app/pages/SQLBuilderPage/index.jsx +390 -0
  93. package/src/app/providers/djclient.jsx +5 -0
  94. package/src/app/services/DJService.js +388 -22
  95. package/src/app/services/__tests__/DJService.test.jsx +609 -0
  96. package/src/mocks/mockNodes.jsx +1397 -0
  97. package/src/setupTests.ts +31 -1
  98. package/src/styles/dag.css +111 -5
  99. package/src/styles/index.css +467 -31
  100. package/src/styles/login.css +67 -0
  101. package/src/styles/node-creation.scss +197 -0
  102. package/src/styles/styles.scss +44 -0
  103. package/src/styles/styles.scss.d.ts +9 -0
  104. package/src/utils/form.jsx +23 -0
  105. package/tsconfig.json +1 -5
  106. package/webpack.config.js +29 -6
  107. package/.babelrc +0 -4
  108. package/.env.local +0 -4
  109. package/.env.production +0 -1
  110. package/.github/pull_request_template.md +0 -11
  111. package/.github/workflows/ci.yml +0 -33
  112. package/.vscode/extensions.json +0 -7
  113. package/.vscode/launch.json +0 -15
  114. package/.vscode/settings.json +0 -25
  115. package/Dockerfile +0 -7
  116. package/dist/5fa71a03d45dc2e3d61447f3013a303d.png +0 -0
  117. package/dist/index.html +0 -1
  118. package/dist/main.js +0 -23303
  119. package/dist/static/main.05a86d446163fd5f17d3.js +0 -2
  120. package/dist/static/main.05a86d446163fd5f17d3.js.LICENSE.txt +0 -98
  121. package/dist/static/main.9e53bed734dae98e5b10.js +0 -2
  122. package/dist/static/main.9e53bed734dae98e5b10.js.LICENSE.txt +0 -98
  123. package/dist/static/main.js +0 -2
  124. package/dist/static/main.js.LICENSE.txt +0 -98
  125. package/dist/static/vendor.05a86d446163fd5f17d3.js +0 -2
  126. package/dist/static/vendor.05a86d446163fd5f17d3.js.LICENSE.txt +0 -29
  127. package/dist/static/vendor.9e53bed734dae98e5b10.js +0 -2
  128. package/dist/static/vendor.9e53bed734dae98e5b10.js.LICENSE.txt +0 -29
  129. package/dist/static/vendor.js +0 -2
  130. package/dist/static/vendor.js.LICENSE.txt +0 -29
  131. package/dist/vendor.js +0 -281
  132. package/src/app/pages/ListNamespacesPage/Loadable.jsx +0 -14
  133. package/src/app/pages/ListNamespacesPage/index.jsx +0 -52
  134. package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +0 -45
  135. package/src/app/pages/NamespacePage/__tests__/index.test.tsx +0 -14
@@ -1,51 +1,350 @@
1
1
  import { MarkerType } from 'reactflow';
2
2
 
3
- const DJ_URL = 'http://localhost:8000'; //process.env.REACT_APP_DJ_URL;
3
+ const DJ_URL = process.env.REACT_APP_DJ_URL
4
+ ? process.env.REACT_APP_DJ_URL
5
+ : 'http://localhost:8000';
4
6
 
5
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}/basic/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
+
6
29
  node: async function (name) {
7
- const data = await (await fetch(DJ_URL + '/nodes/' + name + '/')).json();
30
+ const data = await (
31
+ await fetch(`${DJ_URL}/nodes/${name}/`, {
32
+ credentials: 'include',
33
+ })
34
+ ).json();
35
+ if (data.message !== undefined) {
36
+ return data;
37
+ }
38
+ data.primary_key = data.columns
39
+ .filter(col =>
40
+ col.attributes.some(attr => attr.attribute_type.name === 'primary_key'),
41
+ )
42
+ .map(col => col.name);
8
43
  return data;
9
44
  },
10
45
 
46
+ nodes: async function (prefix) {
47
+ return await (
48
+ await fetch(`${DJ_URL}/nodes/?prefix=${prefix}`, {
49
+ credentials: 'include',
50
+ })
51
+ ).json();
52
+ },
53
+
54
+ createNode: async function (
55
+ nodeType,
56
+ name,
57
+ display_name,
58
+ description,
59
+ query,
60
+ mode,
61
+ namespace,
62
+ primary_key,
63
+ ) {
64
+ const response = await fetch(`${DJ_URL}/nodes/${nodeType}`, {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ },
69
+ body: JSON.stringify({
70
+ name: name,
71
+ display_name: display_name,
72
+ description: description,
73
+ query: query,
74
+ mode: mode,
75
+ namespace: namespace,
76
+ primary_key: primary_key,
77
+ }),
78
+ credentials: 'include',
79
+ });
80
+ return { status: response.status, json: await response.json() };
81
+ },
82
+
83
+ patchNode: async function (
84
+ name,
85
+ display_name,
86
+ description,
87
+ query,
88
+ mode,
89
+ primary_key,
90
+ ) {
91
+ try {
92
+ const response = await fetch(`${DJ_URL}/nodes/${name}`, {
93
+ method: 'PATCH',
94
+ headers: {
95
+ 'Content-Type': 'application/json',
96
+ },
97
+ body: JSON.stringify({
98
+ display_name: display_name,
99
+ description: description,
100
+ query: query,
101
+ mode: mode,
102
+ primary_key: primary_key,
103
+ }),
104
+ credentials: 'include',
105
+ });
106
+ return { status: response.status, json: await response.json() };
107
+ } catch (error) {
108
+ return { status: 500, json: { message: 'Update failed' } };
109
+ }
110
+ },
111
+
112
+ registerTable: async function (catalog, schema, table) {
113
+ const response = await fetch(
114
+ `${DJ_URL}/register/table/${catalog}/${schema}/${table}`,
115
+ {
116
+ method: 'POST',
117
+ headers: {
118
+ 'Content-Type': 'application/json',
119
+ },
120
+ credentials: 'include',
121
+ },
122
+ );
123
+ return { status: response.status, json: await response.json() };
124
+ },
125
+
11
126
  upstreams: async function (name) {
12
- const data = await (
13
- await fetch(DJ_URL + '/nodes/' + name + '/upstream/')
127
+ return await (
128
+ await fetch(`${DJ_URL}/nodes/${name}/upstream/`, {
129
+ credentials: 'include',
130
+ })
14
131
  ).json();
15
- return data;
16
132
  },
17
133
 
18
134
  downstreams: async function (name) {
19
- const data = await (
20
- await fetch(DJ_URL + '/nodes/' + name + '/downstream/')
135
+ return await (
136
+ await fetch(`${DJ_URL}/nodes/${name}/downstream/`, {
137
+ credentials: 'include',
138
+ })
139
+ ).json();
140
+ },
141
+
142
+ node_dag: async function (name) {
143
+ return await (
144
+ await fetch(`${DJ_URL}/nodes/${name}/dag/`, {
145
+ credentials: 'include',
146
+ })
147
+ ).json();
148
+ },
149
+
150
+ node_lineage: async function (name) {
151
+ return await (
152
+ await fetch(`${DJ_URL}/nodes/${name}/lineage/`, {
153
+ credentials: 'include',
154
+ })
21
155
  ).json();
22
- return data;
23
156
  },
24
157
 
25
158
  metric: async function (name) {
26
- const data = await (await fetch(DJ_URL + '/metrics/' + name + '/')).json();
27
- return data;
159
+ return await (
160
+ await fetch(`${DJ_URL}/metrics/${name}/`, {
161
+ credentials: 'include',
162
+ })
163
+ ).json();
164
+ },
165
+
166
+ clientCode: async function (name) {
167
+ return await (
168
+ await fetch(`${DJ_URL}/datajunction-clients/python/new_node/${name}`, {
169
+ credentials: 'include',
170
+ })
171
+ ).json();
172
+ },
173
+
174
+ cube: async function (name) {
175
+ return await (
176
+ await fetch(`${DJ_URL}/cubes/${name}/`, {
177
+ credentials: 'include',
178
+ })
179
+ ).json();
180
+ },
181
+
182
+ metrics: async function (name) {
183
+ return await (
184
+ await fetch(`${DJ_URL}/metrics/`, {
185
+ credentials: 'include',
186
+ })
187
+ ).json();
188
+ },
189
+
190
+ commonDimensions: async function (metrics) {
191
+ const metricsQuery = '?' + metrics.map(m => `metric=${m}`).join('&');
192
+ return await (
193
+ await fetch(`${DJ_URL}/metrics/common/dimensions/${metricsQuery}`, {
194
+ credentials: 'include',
195
+ })
196
+ ).json();
197
+ },
198
+
199
+ history: async function (type, name, offset, limit) {
200
+ return await (
201
+ await fetch(
202
+ `${DJ_URL}/history?node=${name}&offset=${offset ? offset : 0}&limit=${
203
+ limit ? limit : 100
204
+ }`,
205
+ {
206
+ credentials: 'include',
207
+ },
208
+ )
209
+ ).json();
210
+ },
211
+
212
+ revisions: async function (name) {
213
+ return await (
214
+ await fetch(`${DJ_URL}/nodes/${name}/revisions/`, {
215
+ credentials: 'include',
216
+ })
217
+ ).json();
28
218
  },
29
219
 
30
220
  namespace: async function (nmspce) {
31
- const data = await (
32
- await fetch(DJ_URL + '/namespaces/' + nmspce + '/')
221
+ return await (
222
+ await fetch(`${DJ_URL}/namespaces/${nmspce}/`, {
223
+ credentials: 'include',
224
+ })
33
225
  ).json();
34
- return data;
35
226
  },
36
227
 
37
228
  namespaces: async function () {
38
- const data = await (await fetch(DJ_URL + '/namespaces/')).json();
39
- return data;
229
+ return await (
230
+ await fetch(`${DJ_URL}/namespaces/`, {
231
+ credentials: 'include',
232
+ })
233
+ ).json();
234
+ },
235
+
236
+ sql: async function (metric_name, selection) {
237
+ return await (
238
+ await fetch(
239
+ `${DJ_URL}/sql/${metric_name}?` + new URLSearchParams(selection),
240
+ {
241
+ credentials: 'include',
242
+ },
243
+ )
244
+ ).json();
245
+ },
246
+
247
+ nodesWithDimension: async function (name) {
248
+ return await (
249
+ await fetch(`${DJ_URL}/dimensions/${name}/nodes/`, {
250
+ credentials: 'include',
251
+ })
252
+ ).json();
253
+ },
254
+
255
+ materializations: async function (node) {
256
+ const data = await (
257
+ await fetch(`${DJ_URL}/nodes/${node}/materializations/`, {
258
+ credentials: 'include',
259
+ })
260
+ ).json();
261
+
262
+ return await Promise.all(
263
+ data.map(async materialization => {
264
+ materialization.clientCode = await (
265
+ await fetch(
266
+ `${DJ_URL}/datajunction-clients/python/add_materialization/${node}/${materialization.name}`,
267
+ {
268
+ credentials: 'include',
269
+ },
270
+ )
271
+ ).json();
272
+ return materialization;
273
+ }),
274
+ );
275
+ },
276
+
277
+ columns: async function (node) {
278
+ return await Promise.all(
279
+ node.columns.map(async col => {
280
+ if (col.dimension) {
281
+ col.clientCode = await (
282
+ await fetch(
283
+ `${DJ_URL}/datajunction-clients/python/link_dimension/${node.name}/${col.name}/${col.dimension?.name}`,
284
+ {
285
+ credentials: 'include',
286
+ },
287
+ )
288
+ ).json();
289
+ }
290
+ return col;
291
+ }),
292
+ );
293
+ },
294
+
295
+ sqls: async function (metricSelection, dimensionSelection, filters) {
296
+ const params = new URLSearchParams();
297
+ metricSelection.map(metric => params.append('metrics', metric));
298
+ dimensionSelection.map(dimension => params.append('dimensions', dimension));
299
+ params.append('filters', filters);
300
+ return await (
301
+ await fetch(`${DJ_URL}/sql/?${params}`, {
302
+ credentials: 'include',
303
+ })
304
+ ).json();
305
+ },
306
+
307
+ data: async function (metricSelection, dimensionSelection) {
308
+ const params = new URLSearchParams();
309
+ metricSelection.map(metric => params.append('metrics', metric));
310
+ dimensionSelection.map(dimension => params.append('dimensions', dimension));
311
+ return await (
312
+ await fetch(`${DJ_URL}/data/?` + params + '&limit=10000', {
313
+ credentials: 'include',
314
+ })
315
+ ).json();
316
+ },
317
+
318
+ stream: async function (metricSelection, dimensionSelection, filters) {
319
+ const params = new URLSearchParams();
320
+ metricSelection.map(metric => params.append('metrics', metric));
321
+ dimensionSelection.map(dimension => params.append('dimensions', dimension));
322
+ params.append('filters', filters);
323
+ return new EventSource(
324
+ `${DJ_URL}/stream/?${params}&limit=10000&async_=true`,
325
+ {
326
+ withCredentials: true,
327
+ },
328
+ );
40
329
  },
41
330
 
42
331
  lineage: async function (node) {},
43
332
 
333
+ compiledSql: async function (node) {
334
+ return await (
335
+ await fetch(`${DJ_URL}/sql/${node}/`, {
336
+ credentials: 'include',
337
+ })
338
+ ).json();
339
+ },
340
+
44
341
  dag: async function (namespace = 'default') {
45
342
  const edges = [];
46
- const data = await (await fetch(DJ_URL + '/nodes/')).json();
47
-
48
- // const metrics = await (await fetch(DJ_URL + '/metrics/')).json();
343
+ const data = await (
344
+ await fetch(`${DJ_URL}/nodes/`, {
345
+ credentials: 'include',
346
+ })
347
+ ).json();
49
348
 
50
349
  data.forEach(obj => {
51
350
  obj.parents.forEach(parent => {
@@ -97,7 +396,6 @@ export const DataJunctionAPI = {
97
396
  const column_names = node.columns.map(col => {
98
397
  return { name: col.name, type: col.type };
99
398
  });
100
- // const dimensions = node.type === "metric" ? metrics.filter(metric => metric.name === node.name)[0].dimensions : [];
101
399
  return {
102
400
  id: String(node.name),
103
401
  type: 'DJNode',
@@ -112,13 +410,81 @@ export const DataJunctionAPI = {
112
410
  type: node.type,
113
411
  primary_key: primary_key,
114
412
  column_names: column_names,
115
- // dimensions: dimensions,
116
413
  },
117
- // parentNode: [node.name.split(".").slice(-2, -1)],
118
- // extent: 'parent',
119
414
  };
120
415
  });
121
416
 
122
417
  return { edges: edges, nodes: nodes, namespaces: namespaceNodes };
123
418
  },
419
+ attributes: async function () {
420
+ return await (
421
+ await fetch(`${DJ_URL}/attributes`, {
422
+ credentials: 'include',
423
+ })
424
+ ).json();
425
+ },
426
+ setAttributes: async function (nodeName, columnName, attributes) {
427
+ const response = await fetch(
428
+ `${DJ_URL}/nodes/${nodeName}/columns/${columnName}/attributes`,
429
+ {
430
+ method: 'POST',
431
+ headers: {
432
+ 'Content-Type': 'application/json',
433
+ },
434
+ body: JSON.stringify(
435
+ attributes.map(attribute => {
436
+ return {
437
+ namespace: 'system',
438
+ name: attribute,
439
+ };
440
+ }),
441
+ ),
442
+ credentials: 'include',
443
+ },
444
+ );
445
+ return { status: response.status, json: await response.json() };
446
+ },
447
+ dimensions: async function () {
448
+ return await (
449
+ await fetch(`${DJ_URL}/dimensions`, {
450
+ credentials: 'include',
451
+ })
452
+ ).json();
453
+ },
454
+ linkDimension: async function (nodeName, columnName, dimensionName) {
455
+ const response = await fetch(
456
+ `${DJ_URL}/nodes/${nodeName}/columns/${columnName}?dimension=${dimensionName}`,
457
+ {
458
+ method: 'POST',
459
+ headers: {
460
+ 'Content-Type': 'application/json',
461
+ },
462
+ credentials: 'include',
463
+ },
464
+ );
465
+ return { status: response.status, json: await response.json() };
466
+ },
467
+ unlinkDimension: async function (nodeName, columnName, dimensionName) {
468
+ const response = await fetch(
469
+ `${DJ_URL}/nodes/${nodeName}/columns/${columnName}?dimension=${dimensionName}`,
470
+ {
471
+ method: 'DELETE',
472
+ headers: {
473
+ 'Content-Type': 'application/json',
474
+ },
475
+ credentials: 'include',
476
+ },
477
+ );
478
+ return { status: response.status, json: await response.json() };
479
+ },
480
+ deactivate: async function (nodeName) {
481
+ const response = await fetch(`${DJ_URL}/nodes/${nodeName}`, {
482
+ method: 'DELETE',
483
+ headers: {
484
+ 'Content-Type': 'application/json',
485
+ },
486
+ credentials: 'include',
487
+ });
488
+ return { status: response.status, json: await response.json() };
489
+ },
124
490
  };