datajunction-ui 0.0.31 → 0.0.41
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 +3 -3
- package/src/app/components/ListGroupItem.jsx +2 -2
- package/src/app/components/QueryInfo.jsx +2 -1
- package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +2 -2
- package/src/app/components/djgraph/__tests__/Collapse.test.jsx +6 -3
- package/src/app/pages/AddEditNodePage/index.jsx +1 -1
- package/src/app/pages/AddEditTagPage/index.jsx +1 -1
- package/src/app/pages/CubeBuilderPage/__tests__/index.test.jsx +55 -21
- package/src/app/pages/NodePage/NodeInfoTab.jsx +17 -6
- package/src/app/pages/NodePage/NodeMaterializationTab.jsx +5 -0
- package/src/app/pages/NodePage/NodePreAggregationsTab.jsx +656 -0
- package/src/app/pages/NodePage/NodeValidateTab.jsx +4 -2
- package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +58 -45
- package/src/app/pages/NodePage/__tests__/NodePreAggregationsTab.test.jsx +654 -0
- package/src/app/pages/NodePage/index.jsx +9 -1
- package/src/app/pages/NotificationsPage/__tests__/index.test.jsx +19 -4
- package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +47 -9
- package/src/app/pages/SQLBuilderPage/index.jsx +2 -2
- package/src/app/services/DJService.js +26 -0
- package/src/styles/preaggregations.css +547 -0
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datajunction-ui",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "DataJunction
|
|
3
|
+
"version": "0.0.41",
|
|
4
|
+
"description": "DataJunction UI",
|
|
5
5
|
"module": "src/index.tsx",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/DataJunction/dj
|
|
8
|
+
"url": "git+https://github.com/DataJunction/dj.git"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
11
|
"datajunction",
|
|
@@ -9,14 +9,14 @@ export default class ListGroupItem extends Component {
|
|
|
9
9
|
<div className="d-flex gap-2 w-100 justify-content-between py-3">
|
|
10
10
|
<div>
|
|
11
11
|
<h6 className="mb-0 w-100">{label}</h6>
|
|
12
|
-
<
|
|
12
|
+
<div
|
|
13
13
|
className="mb-0 opacity-75"
|
|
14
14
|
role="dialog"
|
|
15
15
|
aria-hidden="false"
|
|
16
16
|
aria-label={label}
|
|
17
17
|
>
|
|
18
18
|
<Markdown>{value}</Markdown>
|
|
19
|
-
</
|
|
19
|
+
</div>
|
|
20
20
|
</div>
|
|
21
21
|
</div>
|
|
22
22
|
</div>
|
|
@@ -122,8 +122,9 @@ export default function QueryInfo({
|
|
|
122
122
|
<li className={'query-info'}>
|
|
123
123
|
<label>Logs</label>{' '}
|
|
124
124
|
{errors?.length ? (
|
|
125
|
-
errors.map(error => (
|
|
125
|
+
errors.map((error, idx) => (
|
|
126
126
|
<div
|
|
127
|
+
key={`error-${idx}`}
|
|
127
128
|
style={{
|
|
128
129
|
height: '800px',
|
|
129
130
|
width: '80%',
|
|
@@ -13,7 +13,7 @@ exports[`<ListGroupItem /> should render and match the snapshot 1`] = `
|
|
|
13
13
|
>
|
|
14
14
|
Name
|
|
15
15
|
</h6>
|
|
16
|
-
<
|
|
16
|
+
<div
|
|
17
17
|
aria-hidden="false"
|
|
18
18
|
aria-label="Name"
|
|
19
19
|
className="mb-0 opacity-75"
|
|
@@ -24,7 +24,7 @@ exports[`<ListGroupItem /> should render and match the snapshot 1`] = `
|
|
|
24
24
|
Something
|
|
25
25
|
</span>
|
|
26
26
|
</Markdown>
|
|
27
|
-
</
|
|
27
|
+
</div>
|
|
28
28
|
</div>
|
|
29
29
|
</div>
|
|
30
30
|
</div>
|
|
@@ -35,10 +35,13 @@ describe('<Collapse />', () => {
|
|
|
35
35
|
<Collapse
|
|
36
36
|
{...defaultProps}
|
|
37
37
|
data={{
|
|
38
|
+
name: 'test.transform',
|
|
38
39
|
type: 'transform',
|
|
39
|
-
column_names: Array(11
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
column_names: Array.from({ length: 11 }, (_, idx) => ({
|
|
41
|
+
name: `column_${idx}`,
|
|
42
|
+
type: 'string',
|
|
43
|
+
order: idx,
|
|
44
|
+
})),
|
|
42
45
|
primary_key: [],
|
|
43
46
|
}}
|
|
44
47
|
/>
|
|
@@ -185,30 +185,48 @@ describe('CubeBuilderPage', () => {
|
|
|
185
185
|
jest.clearAllMocks();
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
-
it('renders without crashing', () => {
|
|
188
|
+
it('renders without crashing', async () => {
|
|
189
189
|
render(
|
|
190
190
|
<DJClientContext.Provider value={{ DataJunctionAPI: mockDjClient }}>
|
|
191
191
|
<CubeBuilderPage />
|
|
192
192
|
</DJClientContext.Provider>,
|
|
193
193
|
);
|
|
194
|
+
|
|
195
|
+
// Wait for async effects to complete
|
|
196
|
+
await waitFor(() => {
|
|
197
|
+
expect(mockDjClient.metrics).toHaveBeenCalled();
|
|
198
|
+
});
|
|
199
|
+
|
|
194
200
|
expect(screen.getByText('Cube')).toBeInTheDocument();
|
|
195
201
|
});
|
|
196
202
|
|
|
197
|
-
it('renders the Metrics section', () => {
|
|
203
|
+
it('renders the Metrics section', async () => {
|
|
198
204
|
render(
|
|
199
205
|
<DJClientContext.Provider value={{ DataJunctionAPI: mockDjClient }}>
|
|
200
206
|
<CubeBuilderPage />
|
|
201
207
|
</DJClientContext.Provider>,
|
|
202
208
|
);
|
|
209
|
+
|
|
210
|
+
// Wait for async effects to complete
|
|
211
|
+
await waitFor(() => {
|
|
212
|
+
expect(mockDjClient.metrics).toHaveBeenCalled();
|
|
213
|
+
});
|
|
214
|
+
|
|
203
215
|
expect(screen.getByText('Metrics *')).toBeInTheDocument();
|
|
204
216
|
});
|
|
205
217
|
|
|
206
|
-
it('renders the Dimensions section', () => {
|
|
218
|
+
it('renders the Dimensions section', async () => {
|
|
207
219
|
render(
|
|
208
220
|
<DJClientContext.Provider value={{ DataJunctionAPI: mockDjClient }}>
|
|
209
221
|
<CubeBuilderPage />
|
|
210
222
|
</DJClientContext.Provider>,
|
|
211
223
|
);
|
|
224
|
+
|
|
225
|
+
// Wait for async effects to complete
|
|
226
|
+
await waitFor(() => {
|
|
227
|
+
expect(mockDjClient.metrics).toHaveBeenCalled();
|
|
228
|
+
});
|
|
229
|
+
|
|
212
230
|
expect(screen.getByText('Dimensions *')).toBeInTheDocument();
|
|
213
231
|
});
|
|
214
232
|
|
|
@@ -237,22 +255,31 @@ describe('CubeBuilderPage', () => {
|
|
|
237
255
|
}
|
|
238
256
|
fireEvent.click(screen.getAllByText('Dimensions *')[0]);
|
|
239
257
|
|
|
240
|
-
|
|
258
|
+
// Wait for commonDimensions to be called and state to update
|
|
259
|
+
await waitFor(() => {
|
|
260
|
+
expect(mockDjClient.commonDimensions).toHaveBeenCalled();
|
|
261
|
+
});
|
|
241
262
|
|
|
242
263
|
const selectDimensions = screen.getAllByTestId('select-dimensions')[0];
|
|
243
264
|
expect(selectDimensions).toBeDefined();
|
|
244
265
|
expect(selectDimensions).not.toBeNull();
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
266
|
+
|
|
267
|
+
await waitFor(() => {
|
|
268
|
+
expect(
|
|
269
|
+
screen.getByText(
|
|
270
|
+
'default.repair_order_details.repair_order_id → default.repair_order.hard_hat_id → default.hard_hat.birth_date',
|
|
271
|
+
),
|
|
272
|
+
).toBeInTheDocument();
|
|
273
|
+
});
|
|
250
274
|
|
|
251
275
|
const selectDimensionsDate = screen.getAllByTestId(
|
|
252
276
|
'dimensions-default.date_dim',
|
|
253
277
|
)[0];
|
|
254
278
|
|
|
255
279
|
fireEvent.keyDown(selectDimensionsDate.firstChild, { key: 'ArrowDown' });
|
|
280
|
+
await waitFor(() => {
|
|
281
|
+
expect(screen.getByText('Day')).toBeInTheDocument();
|
|
282
|
+
});
|
|
256
283
|
fireEvent.click(screen.getByText('Day'));
|
|
257
284
|
fireEvent.click(screen.getByText('Month'));
|
|
258
285
|
fireEvent.click(screen.getByText('Year'));
|
|
@@ -264,9 +291,8 @@ describe('CubeBuilderPage', () => {
|
|
|
264
291
|
})[0];
|
|
265
292
|
expect(createCube).toBeInTheDocument();
|
|
266
293
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
});
|
|
294
|
+
fireEvent.click(createCube);
|
|
295
|
+
|
|
270
296
|
await waitFor(() => {
|
|
271
297
|
expect(mockDjClient.createCube).toHaveBeenCalledWith(
|
|
272
298
|
'',
|
|
@@ -322,22 +348,31 @@ describe('CubeBuilderPage', () => {
|
|
|
322
348
|
|
|
323
349
|
fireEvent.click(screen.getAllByText('Dimensions *')[0]);
|
|
324
350
|
|
|
325
|
-
|
|
351
|
+
// Wait for commonDimensions to be called and state to update
|
|
352
|
+
await waitFor(() => {
|
|
353
|
+
expect(mockDjClient.commonDimensions).toHaveBeenCalled();
|
|
354
|
+
});
|
|
326
355
|
|
|
327
356
|
const selectDimensions = screen.getAllByTestId('select-dimensions')[0];
|
|
328
357
|
expect(selectDimensions).toBeDefined();
|
|
329
358
|
expect(selectDimensions).not.toBeNull();
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
359
|
+
|
|
360
|
+
await waitFor(() => {
|
|
361
|
+
expect(
|
|
362
|
+
screen.getByText(
|
|
363
|
+
'default.repair_order_details.repair_order_id → default.repair_order.hard_hat_id → default.hard_hat.birth_date',
|
|
364
|
+
),
|
|
365
|
+
).toBeInTheDocument();
|
|
366
|
+
});
|
|
335
367
|
|
|
336
368
|
const selectDimensionsDate = screen.getAllByTestId(
|
|
337
369
|
'dimensions-default.date_dim',
|
|
338
370
|
)[0];
|
|
339
371
|
|
|
340
372
|
fireEvent.keyDown(selectDimensionsDate.firstChild, { key: 'ArrowDown' });
|
|
373
|
+
await waitFor(() => {
|
|
374
|
+
expect(screen.getByText('Day')).toBeInTheDocument();
|
|
375
|
+
});
|
|
341
376
|
fireEvent.click(screen.getByText('Day'));
|
|
342
377
|
fireEvent.click(screen.getByText('Month'));
|
|
343
378
|
fireEvent.click(screen.getByText('Year'));
|
|
@@ -349,9 +384,8 @@ describe('CubeBuilderPage', () => {
|
|
|
349
384
|
})[0];
|
|
350
385
|
expect(createCube).toBeInTheDocument();
|
|
351
386
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
});
|
|
387
|
+
fireEvent.click(createCube);
|
|
388
|
+
|
|
355
389
|
await waitFor(() => {
|
|
356
390
|
expect(mockDjClient.patchCube).toHaveBeenCalledWith(
|
|
357
391
|
'default.repair_orders_cube',
|
|
@@ -37,9 +37,13 @@ export default function NodeInfoTab({ node }) {
|
|
|
37
37
|
const [metricInfo, setMetricInfo] = useState(null);
|
|
38
38
|
|
|
39
39
|
const nodeTags = node?.tags.map(tag => (
|
|
40
|
-
<
|
|
40
|
+
<span
|
|
41
|
+
key={tag.name}
|
|
42
|
+
className={'badge tag_value'}
|
|
43
|
+
style={{ marginRight: '4px' }}
|
|
44
|
+
>
|
|
41
45
|
<a href={`/tags/${tag.name}`}>{tag.display_name}</a>
|
|
42
|
-
</
|
|
46
|
+
</span>
|
|
43
47
|
));
|
|
44
48
|
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
45
49
|
|
|
@@ -314,13 +318,19 @@ export default function NodeInfoTab({ node }) {
|
|
|
314
318
|
}
|
|
315
319
|
>
|
|
316
320
|
{node?.type !== 'metric'
|
|
317
|
-
? node?.primary_key?.map(dim => (
|
|
318
|
-
<span
|
|
321
|
+
? node?.primary_key?.map((dim, idx) => (
|
|
322
|
+
<span
|
|
323
|
+
key={`pk-${idx}`}
|
|
324
|
+
className="rounded-pill badge bg-secondary-soft PrimaryKey"
|
|
325
|
+
>
|
|
319
326
|
<a href={`/nodes/${node?.name}`}>{dim}</a>
|
|
320
327
|
</span>
|
|
321
328
|
))
|
|
322
|
-
: node?.required_dimensions?.map(dim => (
|
|
323
|
-
<span
|
|
329
|
+
: node?.required_dimensions?.map((dim, idx) => (
|
|
330
|
+
<span
|
|
331
|
+
key={`rd-${idx}`}
|
|
332
|
+
className="rounded-pill badge bg-secondary-soft PrimaryKey"
|
|
333
|
+
>
|
|
324
334
|
<a href={`/nodes/${node?.upstream_node}`}>{dim.name}</a>
|
|
325
335
|
</span>
|
|
326
336
|
))}
|
|
@@ -341,6 +351,7 @@ export default function NodeInfoTab({ node }) {
|
|
|
341
351
|
<p className="mb-0 opacity-75">
|
|
342
352
|
{node?.owners.map(owner => (
|
|
343
353
|
<span
|
|
354
|
+
key={owner.username}
|
|
344
355
|
className="badge node_type__transform"
|
|
345
356
|
style={{ margin: '2px', fontSize: '16px', cursor: 'pointer' }}
|
|
346
357
|
>
|
|
@@ -11,6 +11,11 @@ import AvailabilityStateBlock from './AvailabilityStateBlock';
|
|
|
11
11
|
|
|
12
12
|
const cronstrue = require('cronstrue');
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Cube materialization tab - shows cube-specific materializations.
|
|
16
|
+
* For non-cube nodes, the parent component (index.jsx) renders
|
|
17
|
+
* NodePreAggregationsTab instead.
|
|
18
|
+
*/
|
|
14
19
|
export default function NodeMaterializationTab({ node, djClient }) {
|
|
15
20
|
const [rawMaterializations, setRawMaterializations] = useState([]);
|
|
16
21
|
const [selectedRevisionTab, setSelectedRevisionTab] = useState(null);
|