datajunction-ui 0.0.1-a94 → 0.0.1-a95
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 +1 -1
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +3 -1
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +11 -8
- package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +10 -16
- package/src/app/pages/AddEditNodePage/index.jsx +39 -48
- package/src/app/pages/NodePage/NodeInfoTab.jsx +0 -1
- package/src/app/services/DJService.js +53 -0
- package/src/mocks/mockNodes.jsx +67 -0
package/package.json
CHANGED
|
@@ -67,7 +67,9 @@ describe('AddEditNodePage submission failed', () => {
|
|
|
67
67
|
|
|
68
68
|
it('for editing a node', async () => {
|
|
69
69
|
const mockDjClient = initializeMockDJClient();
|
|
70
|
-
mockDjClient.DataJunctionAPI.
|
|
70
|
+
mockDjClient.DataJunctionAPI.getNodeForEditing.mockReturnValue(
|
|
71
|
+
mocks.mockGetMetricNode,
|
|
72
|
+
);
|
|
71
73
|
mockDjClient.DataJunctionAPI.patchNode.mockReturnValue({
|
|
72
74
|
status: 500,
|
|
73
75
|
json: { message: 'Update failed' },
|
|
@@ -152,7 +152,9 @@ describe('AddEditNodePage submission succeeded', () => {
|
|
|
152
152
|
it('for editing a transform or dimension node', async () => {
|
|
153
153
|
const mockDjClient = initializeMockDJClient();
|
|
154
154
|
|
|
155
|
-
mockDjClient.DataJunctionAPI.
|
|
155
|
+
mockDjClient.DataJunctionAPI.getNodeForEditing.mockReturnValue(
|
|
156
|
+
mocks.mockGetTransformNode,
|
|
157
|
+
);
|
|
156
158
|
mockDjClient.DataJunctionAPI.patchNode = jest.fn();
|
|
157
159
|
mockDjClient.DataJunctionAPI.patchNode.mockReturnValue({
|
|
158
160
|
status: 201,
|
|
@@ -189,9 +191,9 @@ describe('AddEditNodePage submission succeeded', () => {
|
|
|
189
191
|
'SELECT repair_order_id, municipality_id, hard_hat_id, dispatcher_id FROM default.repair_orders',
|
|
190
192
|
'published',
|
|
191
193
|
[],
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
'',
|
|
195
|
+
'',
|
|
196
|
+
'',
|
|
195
197
|
undefined,
|
|
196
198
|
);
|
|
197
199
|
expect(mockDjClient.DataJunctionAPI.tagsNode).toBeCalledTimes(1);
|
|
@@ -212,8 +214,9 @@ describe('AddEditNodePage submission succeeded', () => {
|
|
|
212
214
|
it('for editing a metric node', async () => {
|
|
213
215
|
const mockDjClient = initializeMockDJClient();
|
|
214
216
|
|
|
215
|
-
mockDjClient.DataJunctionAPI.
|
|
216
|
-
|
|
217
|
+
mockDjClient.DataJunctionAPI.getNodeForEditing.mockReturnValue(
|
|
218
|
+
mocks.mockGetMetricNode,
|
|
219
|
+
);
|
|
217
220
|
mockDjClient.DataJunctionAPI.patchNode = jest.fn();
|
|
218
221
|
mockDjClient.DataJunctionAPI.patchNode.mockReturnValue({
|
|
219
222
|
status: 201,
|
|
@@ -249,10 +252,10 @@ describe('AddEditNodePage submission succeeded', () => {
|
|
|
249
252
|
'Number of repair orders!!!',
|
|
250
253
|
'SELECT count(repair_order_id) FROM default.repair_orders',
|
|
251
254
|
'published',
|
|
252
|
-
[],
|
|
255
|
+
['repair_order_id', 'country'],
|
|
253
256
|
'neutral',
|
|
254
257
|
'unitless',
|
|
255
|
-
|
|
258
|
+
5,
|
|
256
259
|
undefined,
|
|
257
260
|
);
|
|
258
261
|
expect(mockDjClient.DataJunctionAPI.tagsNode).toBeCalledTimes(1);
|
|
@@ -35,6 +35,7 @@ export const initializeMockDJClient = () => {
|
|
|
35
35
|
];
|
|
36
36
|
},
|
|
37
37
|
metrics: {},
|
|
38
|
+
getNodeForEditing: jest.fn(),
|
|
38
39
|
namespaces: () => {
|
|
39
40
|
return [
|
|
40
41
|
{
|
|
@@ -146,7 +147,9 @@ describe('AddEditNodePage', () => {
|
|
|
146
147
|
|
|
147
148
|
it('Edit node page renders with the selected node', async () => {
|
|
148
149
|
const mockDjClient = initializeMockDJClient();
|
|
149
|
-
mockDjClient.DataJunctionAPI.
|
|
150
|
+
mockDjClient.DataJunctionAPI.getNodeForEditing.mockReturnValue(
|
|
151
|
+
mocks.mockGetMetricNode,
|
|
152
|
+
);
|
|
150
153
|
|
|
151
154
|
const element = testElement(mockDjClient);
|
|
152
155
|
renderEditNode(element);
|
|
@@ -175,17 +178,12 @@ describe('AddEditNodePage', () => {
|
|
|
175
178
|
|
|
176
179
|
it('Verify edit page node not found', async () => {
|
|
177
180
|
const mockDjClient = initializeMockDJClient();
|
|
178
|
-
mockDjClient.DataJunctionAPI.
|
|
179
|
-
mockDjClient.DataJunctionAPI.node.mockReturnValue({
|
|
180
|
-
message: 'A node with name `default.num_repair_orders` does not exist.',
|
|
181
|
-
errors: [],
|
|
182
|
-
warnings: [],
|
|
183
|
-
});
|
|
181
|
+
mockDjClient.DataJunctionAPI.getNodeForEditing.mockReturnValue(null);
|
|
184
182
|
const element = testElement(mockDjClient);
|
|
185
183
|
renderEditNode(element);
|
|
186
184
|
|
|
187
185
|
await waitFor(() => {
|
|
188
|
-
expect(mockDjClient.DataJunctionAPI.
|
|
186
|
+
expect(mockDjClient.DataJunctionAPI.getNodeForEditing).toBeCalledTimes(1);
|
|
189
187
|
expect(
|
|
190
188
|
screen.getByText('Node default.num_repair_orders does not exist!'),
|
|
191
189
|
).toBeInTheDocument();
|
|
@@ -194,18 +192,14 @@ describe('AddEditNodePage', () => {
|
|
|
194
192
|
|
|
195
193
|
it('Verify only transforms, metrics, and dimensions can be edited', async () => {
|
|
196
194
|
const mockDjClient = initializeMockDJClient();
|
|
197
|
-
mockDjClient.DataJunctionAPI.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
type: 'source',
|
|
201
|
-
name: 'default.repair_orders',
|
|
202
|
-
display_name: 'Default: Repair Orders',
|
|
203
|
-
});
|
|
195
|
+
mockDjClient.DataJunctionAPI.getNodeForEditing.mockReturnValue(
|
|
196
|
+
mocks.mockGetSourceNode,
|
|
197
|
+
);
|
|
204
198
|
const element = testElement(mockDjClient);
|
|
205
199
|
renderEditNode(element);
|
|
206
200
|
|
|
207
201
|
await waitFor(() => {
|
|
208
|
-
expect(mockDjClient.DataJunctionAPI.
|
|
202
|
+
expect(mockDjClient.DataJunctionAPI.getNodeForEditing).toBeCalledTimes(1);
|
|
209
203
|
expect(
|
|
210
204
|
screen.getByText(
|
|
211
205
|
'Node default.num_repair_orders is of type source and cannot be edited',
|
|
@@ -188,26 +188,35 @@ export function AddEditNodePage({ extensions = {} }) {
|
|
|
188
188
|
};
|
|
189
189
|
|
|
190
190
|
const getExistingNodeData = async name => {
|
|
191
|
-
const
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
data.upstream_node = metric.upstream_node;
|
|
195
|
-
data.expression = metric.expression;
|
|
196
|
-
data.required_dimensions = metric.required_dimensions;
|
|
191
|
+
const node = await djClient.getNodeForEditing(name);
|
|
192
|
+
if (node === null) {
|
|
193
|
+
return { message: `Node ${name} does not exist` };
|
|
197
194
|
}
|
|
198
|
-
|
|
199
|
-
|
|
195
|
+
const baseData = {
|
|
196
|
+
name: node.name,
|
|
197
|
+
type: node.type.toLowerCase(),
|
|
198
|
+
display_name: node.current.displayName,
|
|
199
|
+
description: node.current.description,
|
|
200
|
+
primary_key: node.current.primaryKey,
|
|
201
|
+
query: node.current.query,
|
|
202
|
+
tags: node.tags,
|
|
203
|
+
mode: node.current.mode.toLowerCase(),
|
|
204
|
+
};
|
|
200
205
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
206
|
+
if (node.type === 'METRIC') {
|
|
207
|
+
return {
|
|
208
|
+
...baseData,
|
|
209
|
+
metric_direction: node.current.metricMetadata?.direction?.toLowerCase(),
|
|
210
|
+
metric_unit: node.current.metricMetadata?.unit?.name?.toLowerCase(),
|
|
211
|
+
significant_digits: node.current.metricMetadata?.significantDigits,
|
|
212
|
+
required_dimensions: node.current.requiredDimensions.map(
|
|
213
|
+
dim => dim.name,
|
|
214
|
+
),
|
|
215
|
+
upstream_node: node.current.parents[0]?.name,
|
|
216
|
+
aggregate_expression: node.current.metricMetadata?.expression,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return baseData;
|
|
211
220
|
};
|
|
212
221
|
|
|
213
222
|
const runValidityChecks = (data, setNode, setMessage) => {
|
|
@@ -217,7 +226,6 @@ export function AddEditNodePage({ extensions = {} }) {
|
|
|
217
226
|
setMessage(`Node ${name} does not exist!`);
|
|
218
227
|
return;
|
|
219
228
|
}
|
|
220
|
-
|
|
221
229
|
// Check if node type can be edited
|
|
222
230
|
if (!nodeCanBeEdited(data.type)) {
|
|
223
231
|
setNode(null);
|
|
@@ -246,14 +254,14 @@ export function AddEditNodePage({ extensions = {} }) {
|
|
|
246
254
|
'primary_key',
|
|
247
255
|
'mode',
|
|
248
256
|
'tags',
|
|
249
|
-
'
|
|
257
|
+
'aggregate_expression',
|
|
250
258
|
'upstream_node',
|
|
259
|
+
'metric_unit',
|
|
260
|
+
'metric_direction',
|
|
261
|
+
'significant_digits',
|
|
251
262
|
];
|
|
252
|
-
const primaryKey = primaryKeyFromNode(data);
|
|
253
263
|
fields.forEach(field => {
|
|
254
|
-
if (field === '
|
|
255
|
-
setFieldValue(field, primaryKey);
|
|
256
|
-
} else if (field === 'tags') {
|
|
264
|
+
if (field === 'tags') {
|
|
257
265
|
setFieldValue(
|
|
258
266
|
field,
|
|
259
267
|
data[field].map(tag => tag.name),
|
|
@@ -262,27 +270,6 @@ export function AddEditNodePage({ extensions = {} }) {
|
|
|
262
270
|
setFieldValue(field, data[field] || '', false);
|
|
263
271
|
}
|
|
264
272
|
});
|
|
265
|
-
if (data.metric_metadata?.direction) {
|
|
266
|
-
setFieldValue('metric_direction', data.metric_metadata.direction);
|
|
267
|
-
}
|
|
268
|
-
if (data.metric_metadata?.unit) {
|
|
269
|
-
setFieldValue(
|
|
270
|
-
'metric_unit',
|
|
271
|
-
data.metric_metadata.unit.name.toLowerCase(),
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
if (data.metric_metadata?.significant_digits) {
|
|
275
|
-
setFieldValue(
|
|
276
|
-
'significant_digits',
|
|
277
|
-
data.metric_metadata.significant_digits,
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
if (data.expression) {
|
|
281
|
-
setFieldValue('aggregate_expression', data.expression);
|
|
282
|
-
}
|
|
283
|
-
if (data.upstream_node) {
|
|
284
|
-
setFieldValue('upstream_node', data.upstream_node);
|
|
285
|
-
}
|
|
286
273
|
setNode(data);
|
|
287
274
|
|
|
288
275
|
// For react-select fields, we have to explicitly set the entire
|
|
@@ -290,13 +277,13 @@ export function AddEditNodePage({ extensions = {} }) {
|
|
|
290
277
|
setSelectTags(
|
|
291
278
|
<TagsField
|
|
292
279
|
defaultValue={data.tags.map(t => {
|
|
293
|
-
return { value: t.name, label: t.
|
|
280
|
+
return { value: t.name, label: t.displayName };
|
|
294
281
|
})}
|
|
295
282
|
/>,
|
|
296
283
|
);
|
|
297
284
|
setSelectPrimaryKey(
|
|
298
285
|
<ColumnsSelect
|
|
299
|
-
defaultValue={
|
|
286
|
+
defaultValue={data.primary_key}
|
|
300
287
|
fieldName="primary_key"
|
|
301
288
|
label="Primary Key"
|
|
302
289
|
isMulti={true}
|
|
@@ -409,7 +396,11 @@ export function AddEditNodePage({ extensions = {} }) {
|
|
|
409
396
|
{nodeType === 'metric' || node.type === 'metric' ? (
|
|
410
397
|
<MetricQueryField
|
|
411
398
|
djClient={djClient}
|
|
412
|
-
value={
|
|
399
|
+
value={
|
|
400
|
+
node.aggregate_expression
|
|
401
|
+
? node.aggregate_expression
|
|
402
|
+
: ''
|
|
403
|
+
}
|
|
413
404
|
/>
|
|
414
405
|
) : (
|
|
415
406
|
<NodeQueryField
|
|
@@ -128,6 +128,59 @@ export const DataJunctionAPI = {
|
|
|
128
128
|
return data;
|
|
129
129
|
},
|
|
130
130
|
|
|
131
|
+
getNodeForEditing: async function (name) {
|
|
132
|
+
const query = `
|
|
133
|
+
query GetNodeForEditing($name: String!) {
|
|
134
|
+
findNodes (names: [$name]) {
|
|
135
|
+
name
|
|
136
|
+
type
|
|
137
|
+
current {
|
|
138
|
+
displayName
|
|
139
|
+
description
|
|
140
|
+
primaryKey
|
|
141
|
+
query
|
|
142
|
+
parents { name }
|
|
143
|
+
metricMetadata {
|
|
144
|
+
direction
|
|
145
|
+
unit { name }
|
|
146
|
+
expression
|
|
147
|
+
significantDigits
|
|
148
|
+
incompatibleDruidFunctions
|
|
149
|
+
}
|
|
150
|
+
requiredDimensions {
|
|
151
|
+
name
|
|
152
|
+
}
|
|
153
|
+
mode
|
|
154
|
+
}
|
|
155
|
+
tags {
|
|
156
|
+
name
|
|
157
|
+
displayName
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
|
|
163
|
+
const results = await (
|
|
164
|
+
await fetch(DJ_GQL, {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
headers: {
|
|
167
|
+
'Content-Type': 'application/json',
|
|
168
|
+
},
|
|
169
|
+
credentials: 'include',
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
query,
|
|
172
|
+
variables: {
|
|
173
|
+
name: name,
|
|
174
|
+
},
|
|
175
|
+
}),
|
|
176
|
+
})
|
|
177
|
+
).json();
|
|
178
|
+
if (results.data.findNodes.length === 0) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return results.data.findNodes[0];
|
|
182
|
+
},
|
|
183
|
+
|
|
131
184
|
getMetric: async function (name) {
|
|
132
185
|
const query = `
|
|
133
186
|
query GetMetric($name: String!) {
|
package/src/mocks/mockNodes.jsx
CHANGED
|
@@ -287,6 +287,73 @@ export const mocks = {
|
|
|
287
287
|
aggregate_expression: 'count(repair_order_id)',
|
|
288
288
|
required_dimensions: [],
|
|
289
289
|
},
|
|
290
|
+
|
|
291
|
+
mockGetSourceNode: {
|
|
292
|
+
name: 'default.num_repair_orders',
|
|
293
|
+
type: 'SOURCE',
|
|
294
|
+
current: {
|
|
295
|
+
displayName: 'source.prodhive.dse.playback_f',
|
|
296
|
+
description:
|
|
297
|
+
'This source node was automatically created as a registered table.',
|
|
298
|
+
primaryKey: [],
|
|
299
|
+
parents: [],
|
|
300
|
+
metricMetadata: null,
|
|
301
|
+
requiredDimensions: [],
|
|
302
|
+
mode: 'PUBLISHED',
|
|
303
|
+
},
|
|
304
|
+
tags: [],
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
mockGetMetricNode: {
|
|
308
|
+
name: 'default.num_repair_orders',
|
|
309
|
+
type: 'METRIC',
|
|
310
|
+
current: {
|
|
311
|
+
displayName: 'Default: Num Repair Orders',
|
|
312
|
+
description: 'Number of repair orders',
|
|
313
|
+
primaryKey: ['repair_order_id', 'country'],
|
|
314
|
+
query:
|
|
315
|
+
'SELECT count(repair_order_id) default_DOT_num_repair_orders FROM default.repair_orders',
|
|
316
|
+
parents: [
|
|
317
|
+
{
|
|
318
|
+
name: 'default.repair_orders',
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
metricMetadata: {
|
|
322
|
+
direction: 'NEUTRAL',
|
|
323
|
+
unit: {
|
|
324
|
+
name: 'UNITLESS',
|
|
325
|
+
},
|
|
326
|
+
expression: 'count(repair_order_id)',
|
|
327
|
+
significantDigits: 5,
|
|
328
|
+
incompatibleDruidFunctions: ['IF'],
|
|
329
|
+
},
|
|
330
|
+
requiredDimensions: [],
|
|
331
|
+
mode: 'PUBLISHED',
|
|
332
|
+
},
|
|
333
|
+
tags: [{ name: 'purpose', displayName: 'Purpose' }],
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
mockGetTransformNode: {
|
|
337
|
+
name: 'default.repair_order_transform',
|
|
338
|
+
type: 'TRANSFORM',
|
|
339
|
+
current: {
|
|
340
|
+
displayName: 'Default: Repair Order Transform',
|
|
341
|
+
description: 'Repair order dimension',
|
|
342
|
+
primaryKey: [],
|
|
343
|
+
query:
|
|
344
|
+
'SELECT repair_order_id, municipality_id, hard_hat_id, dispatcher_id FROM default.repair_orders',
|
|
345
|
+
parents: [
|
|
346
|
+
{
|
|
347
|
+
name: 'default.repair_orders',
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
metricMetadata: null,
|
|
351
|
+
requiredDimensions: [],
|
|
352
|
+
mode: 'PUBLISHED',
|
|
353
|
+
},
|
|
354
|
+
tags: [],
|
|
355
|
+
},
|
|
356
|
+
|
|
290
357
|
attributes: [
|
|
291
358
|
{
|
|
292
359
|
uniqueness_scope: [],
|