datajunction-ui 0.0.1-a42.dev0 → 0.0.1-a43

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 (34) hide show
  1. package/package.json +1 -1
  2. package/src/app/index.tsx +1 -0
  3. package/src/app/pages/AddEditNodePage/AlertMessage.jsx +10 -0
  4. package/src/app/pages/AddEditNodePage/DescriptionField.jsx +17 -0
  5. package/src/app/pages/AddEditNodePage/DisplayNameField.jsx +16 -0
  6. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +2 -0
  7. package/src/app/pages/AddEditNodePage/FullNameField.jsx +3 -2
  8. package/src/app/pages/AddEditNodePage/MetricMetadataFields.jsx +60 -0
  9. package/src/app/pages/AddEditNodePage/MetricQueryField.jsx +71 -0
  10. package/src/app/pages/AddEditNodePage/NamespaceField.jsx +40 -0
  11. package/src/app/pages/AddEditNodePage/NodeModeField.jsx +14 -0
  12. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +5 -3
  13. package/src/app/pages/AddEditNodePage/PrimaryKeySelect.jsx +61 -0
  14. package/src/app/pages/AddEditNodePage/RequiredDimensionsSelect.jsx +54 -0
  15. package/src/app/pages/AddEditNodePage/TagsField.jsx +47 -0
  16. package/src/app/pages/AddEditNodePage/UpstreamNodeField.jsx +49 -0
  17. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +1 -0
  18. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +149 -13
  19. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +35 -8
  20. package/src/app/pages/AddEditNodePage/index.jsx +176 -231
  21. package/src/app/pages/CubeBuilderPage/MetricsSelect.jsx +0 -1
  22. package/src/app/pages/NodePage/AddMaterializationPopover.jsx +0 -1
  23. package/src/app/pages/NodePage/NodeHistory.jsx +1 -1
  24. package/src/app/pages/NodePage/NodeInfoTab.jsx +54 -13
  25. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +34 -28
  26. package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +2 -18
  27. package/src/app/pages/NodePage/index.jsx +30 -27
  28. package/src/app/pages/Root/index.tsx +3 -2
  29. package/src/app/services/DJService.js +37 -0
  30. package/src/app/services/__tests__/DJService.test.jsx +23 -0
  31. package/src/mocks/mockNodes.jsx +63 -0
  32. package/src/styles/index.css +6 -0
  33. package/src/styles/node-creation.scss +63 -5
  34. package/dj.internal.db +0 -0
@@ -4,8 +4,10 @@ import fetchMock from 'jest-fetch-mock';
4
4
  import userEvent from '@testing-library/user-event';
5
5
  import {
6
6
  initializeMockDJClient,
7
+ renderCreateMetric,
7
8
  renderCreateNode,
8
9
  renderEditNode,
10
+ renderEditTransformNode,
9
11
  testElement,
10
12
  } from './index.test';
11
13
  import { mocks } from '../../../../mocks/mockNodes';
@@ -21,11 +23,11 @@ describe('AddEditNodePage submission succeeded', () => {
21
23
  window.scrollTo = jest.fn();
22
24
  });
23
25
 
24
- it('for creating a node', async () => {
26
+ it('for creating a dimension/transform node', async () => {
25
27
  const mockDjClient = initializeMockDJClient();
26
28
  mockDjClient.DataJunctionAPI.createNode.mockReturnValue({
27
29
  status: 200,
28
- json: { name: 'default.some_test_metric' },
30
+ json: { name: 'default.some_test_dim' },
29
31
  });
30
32
 
31
33
  mockDjClient.DataJunctionAPI.tagsNode.mockReturnValue({
@@ -43,11 +45,11 @@ describe('AddEditNodePage submission succeeded', () => {
43
45
 
44
46
  await userEvent.type(
45
47
  screen.getByLabelText('Display Name *'),
46
- 'Some Test Metric',
48
+ 'Some Test Dim',
47
49
  );
48
50
  await userEvent.type(
49
51
  screen.getByLabelText('Query *'),
50
- 'SELECT * FROM test',
52
+ 'SELECT a, b, c FROM test',
51
53
  );
52
54
  await userEvent.click(screen.getByText('Create dimension'));
53
55
 
@@ -55,29 +57,162 @@ describe('AddEditNodePage submission succeeded', () => {
55
57
  expect(mockDjClient.DataJunctionAPI.createNode).toBeCalled();
56
58
  expect(mockDjClient.DataJunctionAPI.createNode).toBeCalledWith(
57
59
  'dimension',
58
- 'default.some_test_metric',
59
- 'Some Test Metric',
60
+ 'default.some_test_dim',
61
+ 'Some Test Dim',
60
62
  '',
61
- 'SELECT * FROM test',
63
+ 'SELECT a, b, c FROM test',
62
64
  'draft',
63
65
  'default',
64
66
  null,
65
67
  undefined,
66
68
  undefined,
69
+ undefined,
67
70
  );
68
- expect(screen.getByText(/default.some_test_metric/)).toBeInTheDocument();
71
+ expect(screen.getByText(/default.some_test_dim/)).toBeInTheDocument();
69
72
  });
70
73
 
74
+ // After successful creation, it should return a success message
75
+ expect(screen.getByTestId('success')).toHaveTextContent(
76
+ 'Successfully created node default.some_test_dim',
77
+ );
78
+ }, 60000);
79
+
80
+ it('for creating a metric node', async () => {
81
+ const mockDjClient = initializeMockDJClient();
82
+ mockDjClient.DataJunctionAPI.createNode.mockReturnValue({
83
+ status: 200,
84
+ json: { name: 'default.some_test_metric' },
85
+ });
86
+
87
+ mockDjClient.DataJunctionAPI.tagsNode.mockReturnValue({
88
+ status: 200,
89
+ json: { message: 'Success' },
90
+ });
91
+
92
+ mockDjClient.DataJunctionAPI.nodesWithType
93
+ .mockReturnValueOnce(['default.test1'])
94
+ .mockReturnValueOnce(['default.test2'])
95
+ .mockReturnValueOnce([]);
96
+
97
+ mockDjClient.DataJunctionAPI.listTags.mockReturnValue([
98
+ { name: 'purpose', display_name: 'Purpose' },
99
+ { name: 'intent', display_name: 'Intent' },
100
+ ]);
101
+
102
+ mockDjClient.DataJunctionAPI.listMetricMetadata.mockReturnValue(
103
+ mocks.metricMetadata,
104
+ );
105
+
106
+ const element = testElement(mockDjClient);
107
+ const { container } = renderCreateMetric(element);
108
+
109
+ await userEvent.type(
110
+ screen.getByLabelText('Display Name *'),
111
+ 'Some Test Metric',
112
+ );
113
+ const selectUpstream = screen.getByTestId('select-upstream-node');
114
+ fireEvent.keyDown(selectUpstream.firstChild, { key: 'ArrowDown' });
115
+ fireEvent.click(screen.getByText('default.repair_orders'));
116
+
117
+ await userEvent.type(
118
+ screen.getByLabelText('Aggregate Expression *'),
119
+ 'SUM(a)',
120
+ );
121
+ await userEvent.click(screen.getByText('Create metric'));
122
+
123
+ await waitFor(
124
+ () => {
125
+ expect(mockDjClient.DataJunctionAPI.createNode).toBeCalled();
126
+ expect(mockDjClient.DataJunctionAPI.createNode).toBeCalledWith(
127
+ 'metric',
128
+ 'default.some_test_metric',
129
+ 'Some Test Metric',
130
+ '',
131
+ 'SELECT SUM(a) FROM default.repair_orders',
132
+ 'draft',
133
+ 'default',
134
+ null,
135
+ undefined,
136
+ undefined,
137
+ undefined,
138
+ );
139
+ expect(
140
+ screen.getByText(/default.some_test_metric/),
141
+ ).toBeInTheDocument();
142
+ },
143
+ { timeout: 10000 },
144
+ );
145
+
71
146
  // After successful creation, it should return a success message
72
147
  expect(screen.getByTestId('success')).toHaveTextContent(
73
148
  'Successfully created node default.some_test_metric',
74
149
  );
75
150
  }, 60000);
76
151
 
77
- it('for editing a node', async () => {
152
+ it('for editing a transform or dimension node', async () => {
153
+ const mockDjClient = initializeMockDJClient();
154
+
155
+ mockDjClient.DataJunctionAPI.node.mockReturnValue(mocks.mockTransformNode);
156
+ mockDjClient.DataJunctionAPI.patchNode = jest.fn();
157
+ mockDjClient.DataJunctionAPI.patchNode.mockReturnValue({
158
+ status: 201,
159
+ json: { name: 'default.repair_order_transform', type: 'transform' },
160
+ });
161
+
162
+ mockDjClient.DataJunctionAPI.tagsNode.mockReturnValue({
163
+ status: 200,
164
+ json: { message: 'Success' },
165
+ });
166
+
167
+ mockDjClient.DataJunctionAPI.listTags.mockReturnValue([
168
+ { name: 'purpose', display_name: 'Purpose' },
169
+ { name: 'intent', display_name: 'Intent' },
170
+ ]);
171
+
172
+ const element = testElement(mockDjClient);
173
+ const { getByTestId } = renderEditTransformNode(element);
174
+
175
+ await userEvent.type(screen.getByLabelText('Display Name *'), '!!!');
176
+ await userEvent.type(screen.getByLabelText('Description'), '!!!');
177
+ await userEvent.click(screen.getByText('Save'));
178
+
179
+ const selectTags = getByTestId('select-tags');
180
+ fireEvent.keyDown(selectTags.firstChild, { key: 'ArrowDown' });
181
+ fireEvent.click(screen.getByText('Purpose'));
182
+
183
+ await waitFor(async () => {
184
+ expect(mockDjClient.DataJunctionAPI.patchNode).toBeCalledTimes(1);
185
+ expect(mockDjClient.DataJunctionAPI.patchNode).toBeCalledWith(
186
+ 'default.repair_order_transform',
187
+ 'Default: Repair Order Transform!!!',
188
+ 'Repair order dimension!!!',
189
+ 'SELECT repair_order_id, municipality_id, hard_hat_id, dispatcher_id FROM default.repair_orders',
190
+ 'published',
191
+ [],
192
+ undefined,
193
+ undefined,
194
+ undefined,
195
+ );
196
+ expect(mockDjClient.DataJunctionAPI.tagsNode).toBeCalledTimes(1);
197
+ expect(mockDjClient.DataJunctionAPI.tagsNode).toBeCalledWith(
198
+ 'default.repair_order_transform',
199
+ [],
200
+ );
201
+
202
+ expect(mockDjClient.DataJunctionAPI.listMetricMetadata).toBeCalledTimes(
203
+ 0,
204
+ );
205
+ expect(
206
+ await screen.getByText(/Successfully updated transform node/),
207
+ ).toBeInTheDocument();
208
+ });
209
+ }, 1000000);
210
+
211
+ it('for editing a metric node', async () => {
78
212
  const mockDjClient = initializeMockDJClient();
79
213
 
80
214
  mockDjClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
215
+ mockDjClient.DataJunctionAPI.metric.mockReturnValue(mocks.mockMetricNode);
81
216
  mockDjClient.DataJunctionAPI.patchNode = jest.fn();
82
217
  mockDjClient.DataJunctionAPI.patchNode.mockReturnValue({
83
218
  status: 201,
@@ -102,8 +237,8 @@ describe('AddEditNodePage submission succeeded', () => {
102
237
  await userEvent.click(screen.getByText('Save'));
103
238
 
104
239
  const selectTags = getByTestId('select-tags');
105
- await fireEvent.keyDown(selectTags.firstChild, { key: 'ArrowDown' });
106
- await fireEvent.click(screen.getByText('Purpose'));
240
+ fireEvent.keyDown(selectTags.firstChild, { key: 'ArrowDown' });
241
+ fireEvent.click(screen.getByText('Purpose'));
107
242
 
108
243
  await waitFor(async () => {
109
244
  expect(mockDjClient.DataJunctionAPI.patchNode).toBeCalledTimes(1);
@@ -111,11 +246,12 @@ describe('AddEditNodePage submission succeeded', () => {
111
246
  'default.num_repair_orders',
112
247
  'Default: Num Repair Orders!!!',
113
248
  'Number of repair orders!!!',
114
- 'SELECT count(repair_order_id) default_DOT_num_repair_orders FROM default.repair_orders',
249
+ 'SELECT count(repair_order_id) FROM default.repair_orders',
115
250
  'published',
116
- null,
251
+ [],
117
252
  'neutral',
118
253
  'unitless',
254
+ undefined,
119
255
  );
120
256
  expect(mockDjClient.DataJunctionAPI.tagsNode).toBeCalledTimes(1);
121
257
  expect(mockDjClient.DataJunctionAPI.tagsNode).toBeCalledWith(
@@ -6,7 +6,6 @@ import fetchMock from 'jest-fetch-mock';
6
6
  import { AddEditNodePage } from '../index.jsx';
7
7
  import { mocks } from '../../../../mocks/mockNodes';
8
8
  import DJClientContext from '../../../providers/djclient';
9
- import userEvent from '@testing-library/user-event';
10
9
 
11
10
  fetchMock.enableMocks();
12
11
 
@@ -52,7 +51,13 @@ export const initializeMockDJClient = () => {
52
51
  patchNode: jest.fn(),
53
52
  node: jest.fn(),
54
53
  tagsNode: jest.fn(),
55
- listTags: jest.fn(),
54
+ listTags: jest.fn().mockReturnValue([]),
55
+ metric: jest.fn().mockReturnValue(mocks.mockMetricNode),
56
+ nodesWithType: jest
57
+ .fn()
58
+ .mockReturnValueOnce(['a'])
59
+ .mockReturnValueOnce(['b'])
60
+ .mockReturnValueOnce(['default.repair_orders']),
56
61
  listMetricMetadata: jest.fn().mockReturnValue({
57
62
  directions: ['higher_is_better', 'lower_is_better', 'neutral'],
58
63
  units: [
@@ -82,6 +87,16 @@ export const renderCreateNode = element => {
82
87
  );
83
88
  };
84
89
 
90
+ export const renderCreateMetric = element => {
91
+ return render(
92
+ <MemoryRouter initialEntries={['/create/metric/default']}>
93
+ <Routes>
94
+ <Route path="create/:nodeType/:initialNamespace" element={element} />
95
+ </Routes>
96
+ </MemoryRouter>,
97
+ );
98
+ };
99
+
85
100
  export const renderEditNode = element => {
86
101
  return render(
87
102
  <MemoryRouter initialEntries={['/nodes/default.num_repair_orders/edit']}>
@@ -92,6 +107,18 @@ export const renderEditNode = element => {
92
107
  );
93
108
  };
94
109
 
110
+ export const renderEditTransformNode = element => {
111
+ return render(
112
+ <MemoryRouter
113
+ initialEntries={['/nodes/default.repair_order_transform/edit']}
114
+ >
115
+ <Routes>
116
+ <Route path="nodes/:name/edit" element={element} />
117
+ </Routes>
118
+ </MemoryRouter>,
119
+ );
120
+ };
121
+
95
122
  describe('AddEditNodePage', () => {
96
123
  beforeEach(() => {
97
124
  fetchMock.resetMocks();
@@ -135,12 +162,12 @@ describe('AddEditNodePage', () => {
135
162
  // The description should be populated
136
163
  expect(screen.getByText('Number of repair orders')).toBeInTheDocument();
137
164
 
138
- // The query should be populated
139
- expect(
140
- screen.getByText(
141
- 'SELECT count(repair_order_id) default_DOT_num_repair_orders FROM default.repair_orders',
142
- ),
143
- ).toBeInTheDocument();
165
+ // The upstream node should be populated
166
+ expect(screen.getByText('default.repair_orders')).toBeInTheDocument();
167
+
168
+ // The aggregate expression should be populated
169
+ expect(screen.getByText('count')).toBeInTheDocument();
170
+ expect(screen.getByText('(repair_order_id)')).toBeInTheDocument();
144
171
  });
145
172
  });
146
173