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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datajunction-ui",
3
- "version": "0.0.1a49",
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": 89,
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
- // TODO: we're disabling this for now because it's unclear how performant the dimensions node
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(node, column, referencedDimensionNode, setStatus);
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(name => {
39
- return { value: name, label: name };
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).then(_ => {
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
- // Click on the 'Validate' tab
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
- // Click on 'Run' to run the node query
724
- const runButton = screen.getByText('► Run');
725
- fireEvent.click(runButton);
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
- const infoTab = screen.getByRole('button', { name: 'QueryInfo' });
735
- const resultsTab = screen.getByText('Results');
739
+ const infoTab = screen.getByRole('button', { name: 'QueryInfo' });
740
+ const resultsTab = screen.getByText('Results');
736
741
 
737
- // Initially, the Results tab should be active
738
- expect(resultsTab).toHaveClass('active');
739
- expect(infoTab).not.toHaveClass('active');
742
+ // Initially, the Results tab should be active
743
+ expect(resultsTab).toHaveClass('active');
744
+ expect(infoTab).not.toHaveClass('active');
740
745
 
741
- // Click on the Info tab first
742
- fireEvent.click(infoTab);
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
- // Click on the Results tab
749
- fireEvent.click(resultsTab);
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');