datajunction-ui 0.0.1-a1 → 0.0.1-a100

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 (110) hide show
  1. package/Makefile +7 -1
  2. package/package.json +18 -7
  3. package/public/index.html +1 -1
  4. package/src/app/components/AddNodeDropdown.jsx +44 -0
  5. package/src/app/components/ListGroupItem.jsx +2 -1
  6. package/src/app/components/NodeListActions.jsx +69 -0
  7. package/src/app/components/NodeMaterializationDelete.jsx +80 -0
  8. package/src/app/components/QueryInfo.jsx +96 -1
  9. package/src/app/components/Search.jsx +94 -0
  10. package/src/app/components/__tests__/NodeListActions.test.jsx +94 -0
  11. package/src/app/components/__tests__/Search.test.jsx +63 -0
  12. package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +5 -3
  13. package/src/app/components/djgraph/Collapse.jsx +3 -2
  14. package/src/app/components/djgraph/DJNode.jsx +1 -1
  15. package/src/app/components/djgraph/DJNodeColumns.jsx +5 -1
  16. package/src/app/components/djgraph/LayoutFlow.jsx +5 -3
  17. package/src/app/components/forms/Action.jsx +8 -0
  18. package/src/app/components/forms/NodeNameField.jsx +64 -0
  19. package/src/app/components/search.css +17 -0
  20. package/src/app/icons/AddItemIcon.jsx +16 -0
  21. package/src/app/icons/CommitIcon.jsx +45 -0
  22. package/src/app/icons/DiffIcon.jsx +63 -0
  23. package/src/app/icons/EyeIcon.jsx +20 -0
  24. package/src/app/icons/FilterIcon.jsx +7 -0
  25. package/src/app/icons/JupyterExportIcon.jsx +25 -0
  26. package/src/app/icons/LoadingIcon.jsx +10 -10
  27. package/src/app/icons/PythonIcon.jsx +6 -44
  28. package/src/app/index.tsx +24 -0
  29. package/src/app/pages/AddEditNodePage/AlertMessage.jsx +10 -0
  30. package/src/app/pages/AddEditNodePage/ColumnsSelect.jsx +84 -0
  31. package/src/app/pages/AddEditNodePage/DescriptionField.jsx +17 -0
  32. package/src/app/pages/AddEditNodePage/DisplayNameField.jsx +16 -0
  33. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +5 -0
  34. package/src/app/pages/AddEditNodePage/FullNameField.jsx +3 -2
  35. package/src/app/pages/AddEditNodePage/Loadable.jsx +6 -2
  36. package/src/app/pages/AddEditNodePage/MetricMetadataFields.jsx +75 -0
  37. package/src/app/pages/AddEditNodePage/MetricQueryField.jsx +71 -0
  38. package/src/app/pages/AddEditNodePage/NamespaceField.jsx +40 -0
  39. package/src/app/pages/AddEditNodePage/NodeModeField.jsx +14 -0
  40. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +8 -3
  41. package/src/app/pages/AddEditNodePage/RequiredDimensionsSelect.jsx +54 -0
  42. package/src/app/pages/AddEditNodePage/TagsField.jsx +47 -0
  43. package/src/app/pages/AddEditNodePage/UpstreamNodeField.jsx +49 -0
  44. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +15 -9
  45. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +167 -24
  46. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +55 -25
  47. package/src/app/pages/AddEditNodePage/index.jsx +275 -194
  48. package/src/app/pages/CubeBuilderPage/DimensionsSelect.jsx +154 -0
  49. package/src/app/pages/CubeBuilderPage/Loadable.jsx +16 -0
  50. package/src/app/pages/CubeBuilderPage/MetricsSelect.jsx +77 -0
  51. package/src/app/pages/CubeBuilderPage/__tests__/index.test.jsx +405 -0
  52. package/src/app/pages/CubeBuilderPage/index.jsx +267 -0
  53. package/src/app/pages/NamespacePage/AddNamespacePopover.jsx +5 -5
  54. package/src/app/pages/NamespacePage/Explorer.jsx +6 -2
  55. package/src/app/pages/NamespacePage/FieldControl.jsx +21 -0
  56. package/src/app/pages/NamespacePage/NodeTypeSelect.jsx +30 -0
  57. package/src/app/pages/NamespacePage/TagSelect.jsx +44 -0
  58. package/src/app/pages/NamespacePage/UserSelect.jsx +47 -0
  59. package/src/app/pages/NamespacePage/__tests__/index.test.jsx +98 -19
  60. package/src/app/pages/NamespacePage/index.jsx +272 -89
  61. package/src/app/pages/NodePage/AddBackfillPopover.jsx +61 -61
  62. package/src/app/pages/NodePage/AddMaterializationPopover.jsx +104 -51
  63. package/src/app/pages/NodePage/ClientCodePopover.jsx +73 -25
  64. package/src/app/pages/NodePage/DimensionFilter.jsx +86 -0
  65. package/src/app/pages/NodePage/EditColumnDescriptionPopover.jsx +116 -0
  66. package/src/app/pages/NodePage/LinkDimensionPopover.jsx +38 -23
  67. package/src/app/pages/NodePage/MaterializationConfigField.jsx +60 -0
  68. package/src/app/pages/NodePage/NodeColumnTab.jsx +183 -113
  69. package/src/app/pages/NodePage/NodeDependenciesTab.jsx +153 -0
  70. package/src/app/pages/NodePage/NodeGraphTab.jsx +56 -29
  71. package/src/app/pages/NodePage/NodeHistory.jsx +165 -161
  72. package/src/app/pages/NodePage/NodeInfoTab.jsx +148 -14
  73. package/src/app/pages/NodePage/NodeMaterializationTab.jsx +201 -104
  74. package/src/app/pages/NodePage/NodeStatus.jsx +96 -21
  75. package/src/app/pages/NodePage/NodeValidateTab.jsx +367 -0
  76. package/src/app/pages/NodePage/NotebookDownload.jsx +36 -0
  77. package/src/app/pages/NodePage/PartitionColumnPopover.jsx +3 -5
  78. package/src/app/pages/NodePage/PartitionValueForm.jsx +60 -0
  79. package/src/app/pages/NodePage/RevisionDiff.jsx +209 -0
  80. package/src/app/pages/NodePage/WatchNodeButton.jsx +226 -0
  81. package/src/app/pages/NodePage/__tests__/AddBackfillPopover.test.jsx +13 -4
  82. package/src/app/pages/NodePage/__tests__/AddMaterializationPopover.test.jsx +87 -0
  83. package/src/app/pages/NodePage/__tests__/DimensionFilter.test.jsx +74 -0
  84. package/src/app/pages/NodePage/__tests__/EditColumnDescriptionPopover.test.jsx +149 -0
  85. package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +10 -14
  86. package/src/app/pages/NodePage/__tests__/NodeColumnTab.test.jsx +166 -0
  87. package/src/app/pages/NodePage/__tests__/NodeDependenciesTab.test.jsx +151 -0
  88. package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +6 -2
  89. package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +3 -2
  90. package/src/app/pages/NodePage/__tests__/NodeMaterializationTab.test.jsx +148 -0
  91. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +159 -57
  92. package/src/app/pages/NodePage/__tests__/RevisionDiff.test.jsx +164 -0
  93. package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +2 -386
  94. package/src/app/pages/NodePage/index.jsx +94 -57
  95. package/src/app/pages/Root/__tests__/index.test.jsx +3 -1
  96. package/src/app/pages/Root/index.tsx +62 -12
  97. package/src/app/services/DJService.js +587 -55
  98. package/src/app/services/__tests__/DJService.test.jsx +382 -45
  99. package/src/index.tsx +1 -0
  100. package/src/mocks/mockNodes.jsx +265 -227
  101. package/src/styles/dag.css +4 -2
  102. package/src/styles/index.css +474 -10
  103. package/src/styles/loading.css +1 -1
  104. package/src/styles/node-creation.scss +84 -5
  105. package/src/styles/node-list.css +4 -0
  106. package/src/styles/sorted-table.css +15 -0
  107. package/src/app/components/DeleteNode.jsx +0 -55
  108. package/src/app/components/__tests__/DeleteNode.test.jsx +0 -53
  109. package/src/app/pages/NodePage/NodeSQLTab.jsx +0 -82
  110. package/src/app/pages/NodePage/__tests__/ClientCodePopover.test.jsx +0 -49
@@ -9,6 +9,7 @@ form {
9
9
  padding: 1rem;
10
10
  font-family: Lato, 'sans-serif';
11
11
  font-size: 110%;
12
+ border-right: 16px solid transparent;
12
13
  }
13
14
 
14
15
  input {
@@ -39,6 +40,13 @@ form {
39
40
  padding: 0 20px;
40
41
  }
41
42
 
43
+ .CubeCreationInput {
44
+ margin: 0.5rem 0;
45
+ display: inline-grid;
46
+ width: 75%;
47
+ padding: 0 20px;
48
+ }
49
+
42
50
  .DisplayNameInput,
43
51
  .FullNameInput,
44
52
  .NamespaceInput {
@@ -91,7 +99,7 @@ form {
91
99
  .SelectInput {
92
100
  background-color: #eee;
93
101
  border-radius: 10px;
94
- border-style: none;
102
+ border-style: none !important;
95
103
  border-color: transparent;
96
104
  box-sizing: border-box;
97
105
  padding: 0.5rem;
@@ -99,16 +107,65 @@ form {
99
107
  box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px,
100
108
  rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
101
109
  }
102
- .SelectInput div,
103
- .SelectInput div div {
110
+ .SelectInput div {
104
111
  border: none;
112
+ background: transparent;
105
113
  }
106
-
107
114
  .SelectInput div:first-child {
108
115
  background-color: #eee !important;
109
116
  border: none;
110
117
  color: #0c4128;
111
118
  }
119
+ .SelectInput div:last-child div {
120
+ border: none;
121
+ background-color: #efefef;
122
+ }
123
+ .MultiSelectInput {
124
+ background-color: #eee;
125
+ border-radius: 10px;
126
+ border-style: none;
127
+ border-color: transparent;
128
+ box-sizing: border-box;
129
+ padding: 0.5rem 0;
130
+ font-size: 110%;
131
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px,
132
+ rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
133
+ }
134
+ .MultiSelectInput div {
135
+ border: none;
136
+ background-color: #fff;
137
+ }
138
+ .MultiSelectInput div:last-child div {
139
+ border: none;
140
+ background-color: #efefef;
141
+ }
142
+ .MultiSelectInput div:last-child input {
143
+ box-shadow: none;
144
+ }
145
+ .MultiSelectInput div div {
146
+ border: none;
147
+ background-color: #efefef;
148
+ }
149
+
150
+ .MultiSelectInput div div div,
151
+ .MultiSelectInput div div div:last-child {
152
+ border: none;
153
+ background-color: #ffffff;
154
+ border-radius: 0.4rem;
155
+ padding: 0.2em;
156
+ }
157
+
158
+ .MultiSelectInput div div div:last-child {
159
+ background-color: #efefef;
160
+ }
161
+ .MultiSelectInput div div div div:last-child {
162
+ border: none;
163
+ background-color: #fff;
164
+ }
165
+ .SelectInput div:first-child {
166
+ border: none;
167
+ color: #0c4128;
168
+ }
112
169
 
113
170
  .DescriptionInput {
114
171
  width: 100%;
@@ -131,18 +188,26 @@ form {
131
188
  .QueryInput {
132
189
  width: 75%;
133
190
  }
191
+ .MetricQueryInput {
192
+ height: 200px;
193
+ }
134
194
 
135
195
  .NodeModeInput {
136
196
  select {
137
197
  background-color: #eeeeee;
138
198
  border-radius: 10px;
139
- border-style: none;
140
199
  padding: 1rem;
141
200
  font-family: Lato, Sans;
142
201
  font-size: 110%;
143
202
  }
144
203
  }
145
204
 
205
+ .FullNameField {
206
+ background-color: #fff;
207
+ box-shadow: none;
208
+ color: #7c7c7c;
209
+ }
210
+
146
211
  button {
147
212
  display: block;
148
213
  border-radius: 10px;
@@ -189,9 +254,23 @@ form {
189
254
  }
190
255
  }
191
256
 
257
+ .warning {
258
+ background-color: rgb(253, 248, 242);
259
+ color: rgb(190, 105, 37);
260
+ svg {
261
+ filter: invert(16%) sepia(68%) saturate(2827%) hue-rotate(344deg)
262
+ brightness(96%) contrast(100%);
263
+ }
264
+ }
265
+
192
266
  .SourceCreationInput {
193
267
  margin: 0.5rem 0;
194
268
  display: inline-grid;
195
269
  width: 20%;
196
270
  padding: 0 20px;
197
271
  }
272
+
273
+ .HighlightPath {
274
+ background: #f5efff;
275
+ padding: 5px;
276
+ }
@@ -0,0 +1,4 @@
1
+ table {
2
+ width: 100%;
3
+ height: min-content;
4
+ }
@@ -0,0 +1,15 @@
1
+ .sortable {
2
+ background: none;
3
+ border: none;
4
+ cursor: pointer;
5
+ font-weight: bold;
6
+ font-family: inherit;
7
+ color: inherit;
8
+ text-transform: uppercase;
9
+ }
10
+ .sortable.ascending::after {
11
+ content: ' ▲';
12
+ }
13
+ .sortable.descending::after {
14
+ content: ' ▼';
15
+ }
@@ -1,55 +0,0 @@
1
- import DJClientContext from '../providers/djclient';
2
- import * as React from 'react';
3
- import DeleteIcon from '../icons/DeleteIcon';
4
- import { Form, Formik } from 'formik';
5
- import { useContext } from 'react';
6
- import { displayMessageAfterSubmit } from '../../utils/form';
7
-
8
- export default function DeleteNode({ nodeName }) {
9
- const djClient = useContext(DJClientContext).DataJunctionAPI;
10
- const deleteNode = async (values, { setSubmitting, setStatus }) => {
11
- const { status, json } = await djClient.deactivate(values.nodeName);
12
- if (status === 200 || status === 201 || status === 204) {
13
- setStatus({
14
- success: <>Successfully deleted node {values.nodeName}</>,
15
- });
16
- } else {
17
- setStatus({
18
- failure: `${json.message}`,
19
- });
20
- }
21
- setSubmitting(false);
22
- };
23
-
24
- const initialValues = {
25
- nodeName: nodeName,
26
- };
27
-
28
- return (
29
- <Formik initialValues={initialValues} onSubmit={deleteNode}>
30
- {function Render({ isSubmitting, status, setFieldValue }) {
31
- return (
32
- <Form className="deleteNode">
33
- {displayMessageAfterSubmit(status)}
34
- {
35
- <>
36
- <button
37
- type="submit"
38
- disabled={isSubmitting}
39
- style={{
40
- marginLeft: 0,
41
- all: 'unset',
42
- color: '#005c72',
43
- cursor: 'pointer',
44
- }}
45
- >
46
- <DeleteIcon />
47
- </button>
48
- </>
49
- }
50
- </Form>
51
- );
52
- }}
53
- </Formik>
54
- );
55
- }
@@ -1,53 +0,0 @@
1
- import React from 'react';
2
- import { screen, waitFor } from '@testing-library/react';
3
- import fetchMock from 'jest-fetch-mock';
4
- import userEvent from '@testing-library/user-event';
5
- import { render } from '../../../setupTests';
6
- import DJClientContext from '../../providers/djclient';
7
- import DeleteNode from '../DeleteNode';
8
-
9
- describe('<DeleteNode />', () => {
10
- beforeEach(() => {
11
- fetchMock.resetMocks();
12
- jest.clearAllMocks();
13
- window.scrollTo = jest.fn();
14
- });
15
-
16
- const renderElement = djClient => {
17
- return render(
18
- <DJClientContext.Provider value={djClient}>
19
- <DeleteNode nodeName="default.hard_hat" />
20
- </DJClientContext.Provider>,
21
- );
22
- };
23
-
24
- const initializeMockDJClient = () => {
25
- return {
26
- DataJunctionAPI: {
27
- deactivate: jest.fn(),
28
- },
29
- };
30
- };
31
-
32
- it('deletes a node when clicked', async () => {
33
- const mockDjClient = initializeMockDJClient();
34
- mockDjClient.DataJunctionAPI.deactivate.mockReturnValue({
35
- status: 204,
36
- json: { name: 'source.warehouse.schema.some_table' },
37
- });
38
-
39
- renderElement(mockDjClient);
40
-
41
- await userEvent.click(screen.getByRole('button'));
42
-
43
- await waitFor(() => {
44
- expect(mockDjClient.DataJunctionAPI.deactivate).toBeCalled();
45
- expect(mockDjClient.DataJunctionAPI.deactivate).toBeCalledWith(
46
- 'default.hard_hat',
47
- );
48
- });
49
- expect(
50
- screen.getByText('Successfully deleted node default.hard_hat'),
51
- ).toBeInTheDocument();
52
- }, 60000);
53
- });
@@ -1,82 +0,0 @@
1
- import { useContext, useEffect, useState } from 'react';
2
- import Select from 'react-select';
3
- import DJClientContext from '../../providers/djclient';
4
- import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
5
- import { foundation } from 'react-syntax-highlighter/src/styles/hljs';
6
-
7
- const NodeSQLTab = djNode => {
8
- const djClient = useContext(DJClientContext).DataJunctionAPI;
9
- const [query, setQuery] = useState('');
10
-
11
- const [selection, setSelection] = useState({
12
- dimensions: [],
13
- filters: [],
14
- });
15
-
16
- useEffect(() => {
17
- const fetchData = async () => {
18
- const query = await djClient.sql(djNode.djNode.name, selection);
19
- setQuery(query.sql);
20
- };
21
- fetchData().catch(console.error);
22
- }, [djClient, djNode.djNode.name, selection]);
23
- const dimensionsList = djNode.djNode.dimensions
24
- ? djNode.djNode.dimensions.map(dim => ({
25
- value: dim.name,
26
- label: dim.name + ` (${dim.type})`,
27
- }))
28
- : [''];
29
-
30
- const handleSubmit = event => {
31
- event.preventDefault();
32
- };
33
-
34
- const handleChange = event => {
35
- setSelection({ filters: [], dimensions: event.map(dim => dim.value) });
36
- };
37
-
38
- return (
39
- <form
40
- id="retrieve-sql"
41
- name="retrieve-sql"
42
- onSubmit={handleSubmit.bind(this)}
43
- >
44
- <div>
45
- <h4>Group By</h4>
46
- <Select
47
- name="dimensions"
48
- options={dimensionsList}
49
- isMulti
50
- isClearable
51
- onChange={handleChange}
52
- />
53
- {/*<h4>Filters</h4>*/}
54
- {/*<Select*/}
55
- {/* name="filter_name"*/}
56
- {/* options={dimensionsList}*/}
57
- {/* className="filters_attribute"*/}
58
- {/*/>*/}
59
- {/*<Select*/}
60
- {/* name="filter_operator"*/}
61
- {/* options={options}*/}
62
- {/* className="filters_attribute"*/}
63
- {/*/>*/}
64
- {/*<textarea name="filter_value" className="filters_attribute" />*/}
65
-
66
- <div
67
- style={{
68
- width: window.innerWidth * 0.8,
69
- marginTop: '2rem',
70
- }}
71
- >
72
- <h6 className="mb-0 w-100">Query</h6>
73
- <SyntaxHighlighter language="sql" style={foundation}>
74
- {query}
75
- </SyntaxHighlighter>
76
- </div>
77
- </div>
78
- </form>
79
- );
80
- };
81
-
82
- export default NodeSQLTab;
@@ -1,49 +0,0 @@
1
- import React from 'react';
2
- import { render, fireEvent, screen, waitFor } from '@testing-library/react';
3
- import ClientCodePopover from '../ClientCodePopover';
4
- import userEvent from '@testing-library/user-event';
5
-
6
- describe('<ClientCodePopover />', () => {
7
- const defaultProps = {
8
- code: "print('Hello, World!')",
9
- };
10
-
11
- it('toggles the code popover visibility when the button is clicked', async () => {
12
- render(<ClientCodePopover {...defaultProps} />);
13
-
14
- const button = screen.getByRole('button', 'code-button');
15
-
16
- // Initially, the popover should be hidden
17
- expect(screen.getByRole('dialog', { hidden: true })).toHaveStyle(
18
- 'display: none',
19
- );
20
-
21
- // Clicking the button should display the popover
22
- fireEvent.click(button);
23
- expect(screen.getByRole('dialog', { hidden: true })).not.toHaveStyle(
24
- 'display: none',
25
- );
26
-
27
- // Clicking the button again should hide the popover
28
- fireEvent.click(button);
29
- expect(screen.getByRole('dialog', { hidden: true })).toHaveStyle(
30
- 'display: none',
31
- );
32
-
33
- // Trigger onClose by pressing <escape>
34
- userEvent.keyboard('{Escape}');
35
- // fireEvent.click(screen.getByTestId('body').firstChild());
36
- await waitFor(() => {
37
- expect(screen.getByRole('dialog', { hidden: true })).toHaveStyle(
38
- 'display: none',
39
- );
40
- });
41
- });
42
-
43
- it('renders the provided code within the SyntaxHighlighter', () => {
44
- render(<ClientCodePopover {...defaultProps} />);
45
- expect(screen.getByRole('dialog', { hidden: true })).toHaveTextContent(
46
- defaultProps.code,
47
- );
48
- });
49
- });