datajunction-ui 0.0.1-a49 → 0.0.1-a49.dev2
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 +2 -2
- package/src/app/pages/NodePage/DimensionFilter.jsx +1 -8
- package/src/app/pages/NodePage/LinkDimensionPopover.jsx +13 -5
- package/src/app/pages/NodePage/NodeColumnTab.jsx +5 -3
- package/src/app/pages/NodePage/NodeHistory.jsx +11 -0
- package/src/app/pages/NodePage/NodeValidateTab.jsx +11 -14
- package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +0 -4
- package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +22 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datajunction-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1-a49.dev2",
|
|
4
4
|
"description": "DataJunction Metrics Platform UI",
|
|
5
5
|
"module": "src/index.tsx",
|
|
6
6
|
"repository": {
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
],
|
|
165
165
|
"coverageThreshold": {
|
|
166
166
|
"global": {
|
|
167
|
-
"statements":
|
|
167
|
+
"statements": 87,
|
|
168
168
|
"branches": 75,
|
|
169
169
|
"lines": 80,
|
|
170
170
|
"functions": 85
|
|
@@ -33,14 +33,7 @@ export default function DimensionFilter({ dimension, onChange }) {
|
|
|
33
33
|
)
|
|
34
34
|
.map(col => col.name);
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
// data endpoints are. To re-enable, uncomment the following line:
|
|
38
|
-
// const data = await djClient.nodeData(dimension.metadata.node_name);
|
|
39
|
-
const data = { results: [] };
|
|
40
|
-
|
|
41
|
-
// TODO: when the above is enabled, this will use each dimension node's 'Label' column
|
|
42
|
-
// to build the display label for the dropdown, while continuing to pass the primary
|
|
43
|
-
// key in for filtering
|
|
36
|
+
const data = await djClient.nodeData(dimension.metadata.node_name);
|
|
44
37
|
/* istanbul ignore if */
|
|
45
38
|
if (dimensionNode && data.results && data.results.length > 0) {
|
|
46
39
|
const columnNames = data.results[0].columns.map(
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { useContext, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import DJClientContext from '../../providers/djclient';
|
|
4
|
-
import { Form, Formik } from 'formik';
|
|
4
|
+
import { Field, Form, Formik } from 'formik';
|
|
5
5
|
import { FormikSelect } from '../AddEditNodePage/FormikSelect';
|
|
6
6
|
import EditIcon from '../../icons/EditIcon';
|
|
7
7
|
import { displayMessageAfterSubmit } from '../../../utils/form';
|
|
8
|
+
import LoadingIcon from '../../icons/LoadingIcon';
|
|
8
9
|
|
|
9
10
|
export default function LinkDimensionPopover({
|
|
10
11
|
column,
|
|
@@ -35,11 +36,17 @@ export default function LinkDimensionPopover({
|
|
|
35
36
|
{ node, column, dimension },
|
|
36
37
|
{ setSubmitting, setStatus },
|
|
37
38
|
) => {
|
|
38
|
-
setSubmitting(false);
|
|
39
39
|
if (referencedDimensionNode && dimension === 'Remove') {
|
|
40
|
-
await unlinkDimension(
|
|
40
|
+
await unlinkDimension(
|
|
41
|
+
node,
|
|
42
|
+
column,
|
|
43
|
+
referencedDimensionNode,
|
|
44
|
+
setStatus,
|
|
45
|
+
).then(_ => setSubmitting(false));
|
|
41
46
|
} else {
|
|
42
|
-
await linkDimension(node, column, dimension, setStatus)
|
|
47
|
+
await linkDimension(node, column, dimension, setStatus).then(_ =>
|
|
48
|
+
setSubmitting(false),
|
|
49
|
+
);
|
|
43
50
|
}
|
|
44
51
|
onSubmit();
|
|
45
52
|
};
|
|
@@ -137,8 +144,9 @@ export default function LinkDimensionPopover({
|
|
|
137
144
|
type="submit"
|
|
138
145
|
aria-label="SaveLinkDimension"
|
|
139
146
|
aria-hidden="false"
|
|
147
|
+
disabled={isSubmitting}
|
|
140
148
|
>
|
|
141
|
-
Save
|
|
149
|
+
{isSubmitting ? <LoadingIcon /> : 'Save'}
|
|
142
150
|
</button>
|
|
143
151
|
</Form>
|
|
144
152
|
);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
-
import ClientCodePopover from './ClientCodePopover';
|
|
3
2
|
import * as React from 'react';
|
|
4
3
|
import EditColumnPopover from './EditColumnPopover';
|
|
5
4
|
import LinkDimensionPopover from './LinkDimensionPopover';
|
|
@@ -35,8 +34,11 @@ export default function NodeColumnTab({ node, djClient }) {
|
|
|
35
34
|
useEffect(() => {
|
|
36
35
|
const fetchData = async () => {
|
|
37
36
|
const dimensions = await djClient.dimensions();
|
|
38
|
-
const options = dimensions.map(
|
|
39
|
-
return {
|
|
37
|
+
const options = dimensions.map(dim => {
|
|
38
|
+
return {
|
|
39
|
+
value: dim.name,
|
|
40
|
+
label: `${dim.name} (${dim.indegree} links)`,
|
|
41
|
+
};
|
|
40
42
|
});
|
|
41
43
|
setDimensions(options);
|
|
42
44
|
};
|
|
@@ -74,6 +74,17 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
74
74
|
</div>
|
|
75
75
|
);
|
|
76
76
|
}
|
|
77
|
+
if (event.activity_type === 'refresh') {
|
|
78
|
+
return (
|
|
79
|
+
<div className="history-left">
|
|
80
|
+
<b style={{ textTransform: 'capitalize' }}>{event.activity_type}</b>{' '}
|
|
81
|
+
{event.entity_type}{' '}
|
|
82
|
+
<b>
|
|
83
|
+
<a href={'/nodes/' + event.entity_name}>{event.entity_name}</a>
|
|
84
|
+
</b>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
77
88
|
if (event.activity_type === 'update' && event.entity_type === 'node') {
|
|
78
89
|
return (
|
|
79
90
|
<div className="history-left">
|
|
@@ -93,26 +93,31 @@ export default function NodeValidateTab({ node, djClient }) {
|
|
|
93
93
|
const sse = await djClient.streamNodeData(node?.name, selection);
|
|
94
94
|
sse.onmessage = e => {
|
|
95
95
|
const messageData = JSON.parse(JSON.parse(e.data));
|
|
96
|
+
if (
|
|
97
|
+
messageData !== null &&
|
|
98
|
+
messageData?.state !== 'FINISHED' &&
|
|
99
|
+
messageData?.state !== 'CANCELED' &&
|
|
100
|
+
messageData?.state !== 'FAILED'
|
|
101
|
+
) {
|
|
102
|
+
setRunning(false);
|
|
103
|
+
}
|
|
96
104
|
if (messageData.results && messageData.results?.length > 0) {
|
|
97
105
|
messageData.numRows = messageData.results?.length
|
|
98
106
|
? messageData.results[0].rows.length
|
|
99
107
|
: [];
|
|
100
108
|
switchTab('results');
|
|
109
|
+
setRunning(false);
|
|
101
110
|
} else {
|
|
102
111
|
switchTab('info');
|
|
103
112
|
}
|
|
104
113
|
setQueryInfo(messageData);
|
|
105
114
|
};
|
|
106
115
|
sse.onerror = () => sse.close();
|
|
107
|
-
setRunning(false);
|
|
108
116
|
};
|
|
109
117
|
|
|
110
118
|
// Handle form submission (runs the query)
|
|
111
119
|
const handleSubmit = async (values, { setSubmitting, setStatus }) => {
|
|
112
|
-
await runQuery(values, setStatus, setSubmitting)
|
|
113
|
-
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
|
|
114
|
-
setSubmitting(false);
|
|
115
|
-
});
|
|
120
|
+
await runQuery(values, setStatus, setSubmitting);
|
|
116
121
|
};
|
|
117
122
|
|
|
118
123
|
// Handle when filter values are updated. This is available for all nodes.
|
|
@@ -245,15 +250,7 @@ export default function NodeValidateTab({ node, djClient }) {
|
|
|
245
250
|
className="button-3 execute-button"
|
|
246
251
|
style={{ marginTop: '1rem' }}
|
|
247
252
|
>
|
|
248
|
-
{running
|
|
249
|
-
(queryInfo !== null &&
|
|
250
|
-
queryInfo?.state !== 'FINISHED' &&
|
|
251
|
-
queryInfo?.state !== 'CANCELED' &&
|
|
252
|
-
queryInfo?.state !== 'FAILED') ? (
|
|
253
|
-
<LoadingIcon />
|
|
254
|
-
) : (
|
|
255
|
-
'► Run'
|
|
256
|
-
)}
|
|
253
|
+
{isSubmitting || running === true ? <LoadingIcon /> : '► Run'}
|
|
257
254
|
</button>
|
|
258
255
|
</div>
|
|
259
256
|
<div
|
|
@@ -58,7 +58,6 @@ describe('<LinkDimensionPopover />', () => {
|
|
|
58
58
|
fireEvent.keyDown(linkDimension.firstChild, { key: 'ArrowDown' });
|
|
59
59
|
fireEvent.click(screen.getByText('Dimension 1'));
|
|
60
60
|
fireEvent.click(getByText('Save'));
|
|
61
|
-
getByText('Save').click();
|
|
62
61
|
|
|
63
62
|
// Expect linkDimension to be called
|
|
64
63
|
await waitFor(() => {
|
|
@@ -74,7 +73,6 @@ describe('<LinkDimensionPopover />', () => {
|
|
|
74
73
|
fireEvent.keyDown(linkDimension.firstChild, { key: 'ArrowDown' });
|
|
75
74
|
fireEvent.click(screen.getByText('[Remove dimension link]'));
|
|
76
75
|
fireEvent.click(getByText('Save'));
|
|
77
|
-
getByText('Save').click();
|
|
78
76
|
|
|
79
77
|
// Expect unlinkDimension to be called
|
|
80
78
|
await waitFor(() => {
|
|
@@ -133,7 +131,6 @@ describe('<LinkDimensionPopover />', () => {
|
|
|
133
131
|
fireEvent.keyDown(linkDimension.firstChild, { key: 'ArrowDown' });
|
|
134
132
|
fireEvent.click(screen.getByText('Dimension 1'));
|
|
135
133
|
fireEvent.click(getByText('Save'));
|
|
136
|
-
getByText('Save').click();
|
|
137
134
|
|
|
138
135
|
// Expect linkDimension to be called
|
|
139
136
|
await waitFor(() => {
|
|
@@ -151,7 +148,6 @@ describe('<LinkDimensionPopover />', () => {
|
|
|
151
148
|
fireEvent.keyDown(linkDimension.firstChild, { key: 'ArrowDown' });
|
|
152
149
|
fireEvent.click(screen.getByText('[Remove Dimension]'));
|
|
153
150
|
fireEvent.click(getByText('Save'));
|
|
154
|
-
getByText('Save').click();
|
|
155
151
|
|
|
156
152
|
// Expect unlinkDimension to be called
|
|
157
153
|
await waitFor(() => {
|
|
@@ -706,9 +706,11 @@ describe('<NodePage />', () => {
|
|
|
706
706
|
expect(screen.getByText('Add Filters')).toBeInTheDocument();
|
|
707
707
|
expect(screen.getByText('Generated Query')).toBeInTheDocument();
|
|
708
708
|
expect(screen.getByText('Results')).toBeInTheDocument();
|
|
709
|
+
});
|
|
710
|
+
// Click on the 'Validate' tab
|
|
711
|
+
fireEvent.click(screen.getByRole('button', { name: '► Validate' }));
|
|
709
712
|
|
|
710
|
-
|
|
711
|
-
fireEvent.click(screen.getByRole('button', { name: '► Validate' }));
|
|
713
|
+
await waitFor(() => {
|
|
712
714
|
expect(djClient.DataJunctionAPI.node).toHaveBeenCalledWith(
|
|
713
715
|
mocks.mockMetricNode.name,
|
|
714
716
|
);
|
|
@@ -719,35 +721,41 @@ describe('<NodePage />', () => {
|
|
|
719
721
|
expect(djClient.DataJunctionAPI.nodeDimensions).toHaveBeenCalledWith(
|
|
720
722
|
mocks.mockMetricNode.name,
|
|
721
723
|
);
|
|
724
|
+
});
|
|
722
725
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
+
// Click on 'Run' to run the node query
|
|
727
|
+
const runButton = screen.getByText('► Run');
|
|
728
|
+
fireEvent.click(runButton);
|
|
726
729
|
|
|
730
|
+
await waitFor(() => {
|
|
727
731
|
expect(djClient.DataJunctionAPI.streamNodeData).toHaveBeenCalledWith(
|
|
728
732
|
mocks.mockMetricNode.name,
|
|
729
733
|
{ dimensions: [], filters: [] },
|
|
730
734
|
);
|
|
731
735
|
expect(streamNodeData.onmessage).toBeDefined();
|
|
732
736
|
expect(streamNodeData.onerror).toBeDefined();
|
|
737
|
+
});
|
|
733
738
|
|
|
734
|
-
|
|
735
|
-
|
|
739
|
+
const infoTab = screen.getByRole('button', { name: 'QueryInfo' });
|
|
740
|
+
const resultsTab = screen.getByText('Results');
|
|
736
741
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
742
|
+
// Initially, the Results tab should be active
|
|
743
|
+
expect(resultsTab).toHaveClass('active');
|
|
744
|
+
expect(infoTab).not.toHaveClass('active');
|
|
740
745
|
|
|
741
|
-
|
|
742
|
-
|
|
746
|
+
// Click on the Info tab first
|
|
747
|
+
fireEvent.click(infoTab);
|
|
743
748
|
|
|
749
|
+
await waitFor(() => {
|
|
744
750
|
// Now, the Info tab should be active
|
|
745
751
|
expect(infoTab).toHaveClass('active');
|
|
746
752
|
expect(resultsTab).not.toHaveClass('active');
|
|
753
|
+
});
|
|
747
754
|
|
|
748
|
-
|
|
749
|
-
|
|
755
|
+
// Click on the Results tab
|
|
756
|
+
fireEvent.click(resultsTab);
|
|
750
757
|
|
|
758
|
+
await waitFor(() => {
|
|
751
759
|
// Now, the Results tab should be active again
|
|
752
760
|
expect(resultsTab).toHaveClass('active');
|
|
753
761
|
expect(infoTab).not.toHaveClass('active');
|