datajunction-ui 0.0.1-rc.9 → 0.0.2-0.dev1

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 (244) hide show
  1. package/.env +2 -0
  2. package/.prettierignore +3 -1
  3. package/Makefile +9 -0
  4. package/cleanup-deps.sh +70 -0
  5. package/dj-logo.svg +10 -0
  6. package/package.json +53 -14
  7. package/public/favicon.ico +0 -0
  8. package/public/index.html +1 -1
  9. package/runit.sh +30 -0
  10. package/runit2.sh +30 -0
  11. package/src/__tests__/reportWebVitals.test.jsx +44 -0
  12. package/src/app/__tests__/__snapshots__/index.test.tsx.snap +5 -109
  13. package/src/app/components/AddNodeDropdown.jsx +44 -0
  14. package/src/app/components/ListGroupItem.jsx +9 -1
  15. package/src/app/components/NamespaceHeader.jsx +4 -13
  16. package/src/app/components/NodeListActions.jsx +69 -0
  17. package/src/app/components/NodeMaterializationDelete.jsx +90 -0
  18. package/src/app/components/NotificationBell.tsx +223 -0
  19. package/src/app/components/QueryInfo.jsx +172 -0
  20. package/src/app/components/Search.jsx +94 -0
  21. package/src/app/components/Tab.jsx +8 -1
  22. package/src/app/components/ToggleSwitch.jsx +20 -0
  23. package/src/app/components/UserMenu.tsx +100 -0
  24. package/src/app/components/__tests__/NodeListActions.test.jsx +94 -0
  25. package/src/app/components/__tests__/NodeMaterializationDelete.test.jsx +263 -0
  26. package/src/app/components/__tests__/NotificationBell.test.tsx +302 -0
  27. package/src/app/components/__tests__/QueryInfo.test.jsx +183 -0
  28. package/src/app/components/__tests__/Search.test.jsx +307 -0
  29. package/src/app/components/__tests__/Tab.test.jsx +27 -0
  30. package/src/app/components/__tests__/ToggleSwitch.test.jsx +43 -0
  31. package/src/app/components/__tests__/UserMenu.test.tsx +241 -0
  32. package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +8 -3
  33. package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +2 -18
  34. package/src/app/components/djgraph/Collapse.jsx +47 -0
  35. package/src/app/components/djgraph/DJNode.jsx +61 -83
  36. package/src/app/components/djgraph/DJNodeColumns.jsx +75 -0
  37. package/src/app/components/djgraph/DJNodeDimensions.jsx +75 -0
  38. package/src/app/components/djgraph/LayoutFlow.jsx +106 -0
  39. package/src/app/components/djgraph/__tests__/Collapse.test.jsx +51 -0
  40. package/src/app/components/djgraph/__tests__/DJNodeColumns.test.jsx +83 -0
  41. package/src/app/components/djgraph/__tests__/DJNodeDimensions.test.jsx +118 -0
  42. package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +84 -40
  43. package/src/app/components/forms/Action.jsx +8 -0
  44. package/src/app/components/forms/NodeNameField.jsx +64 -0
  45. package/src/app/components/search.css +17 -0
  46. package/src/app/constants.js +2 -0
  47. package/src/app/icons/AddItemIcon.jsx +16 -0
  48. package/src/app/icons/AlertIcon.jsx +33 -0
  49. package/src/app/icons/CollapsedIcon.jsx +15 -0
  50. package/src/app/icons/CommitIcon.jsx +45 -0
  51. package/src/app/icons/DJLogo.jsx +36 -0
  52. package/src/app/icons/DeleteIcon.jsx +21 -0
  53. package/src/app/icons/DiffIcon.jsx +63 -0
  54. package/src/app/icons/EditIcon.jsx +18 -0
  55. package/src/app/icons/ExpandedIcon.jsx +15 -0
  56. package/src/app/icons/EyeIcon.jsx +20 -0
  57. package/src/app/icons/FilterIcon.jsx +7 -0
  58. package/src/app/icons/HorizontalHierarchyIcon.jsx +15 -0
  59. package/src/app/icons/InvalidIcon.jsx +16 -0
  60. package/src/app/icons/JupyterExportIcon.jsx +25 -0
  61. package/src/app/icons/LoadingIcon.jsx +14 -0
  62. package/src/app/icons/NodeIcon.jsx +49 -0
  63. package/src/app/icons/NotificationIcon.jsx +27 -0
  64. package/src/app/icons/PythonIcon.jsx +14 -0
  65. package/src/app/icons/SettingsIcon.jsx +28 -0
  66. package/src/app/icons/TableIcon.jsx +14 -0
  67. package/src/app/icons/ValidIcon.jsx +16 -0
  68. package/src/app/icons/WrenchIcon.jsx +36 -0
  69. package/src/app/index.tsx +130 -37
  70. package/src/app/pages/AddEditNodePage/AlertMessage.jsx +10 -0
  71. package/src/app/pages/AddEditNodePage/ColumnMetadata.jsx +61 -0
  72. package/src/app/pages/AddEditNodePage/ColumnsMetadataInput.jsx +72 -0
  73. package/src/app/pages/AddEditNodePage/ColumnsSelect.jsx +84 -0
  74. package/src/app/pages/AddEditNodePage/CustomMetadataField.jsx +144 -0
  75. package/src/app/pages/AddEditNodePage/DescriptionField.jsx +17 -0
  76. package/src/app/pages/AddEditNodePage/DisplayNameField.jsx +16 -0
  77. package/src/app/pages/AddEditNodePage/ExperimentationExtension.jsx +338 -0
  78. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +64 -0
  79. package/src/app/pages/AddEditNodePage/FullNameField.jsx +38 -0
  80. package/src/app/pages/AddEditNodePage/Loadable.jsx +20 -0
  81. package/src/app/pages/AddEditNodePage/MetricMetadataFields.jsx +75 -0
  82. package/src/app/pages/AddEditNodePage/MetricQueryField.jsx +71 -0
  83. package/src/app/pages/AddEditNodePage/NamespaceField.jsx +40 -0
  84. package/src/app/pages/AddEditNodePage/NodeModeField.jsx +14 -0
  85. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +94 -0
  86. package/src/app/pages/AddEditNodePage/OwnersField.jsx +54 -0
  87. package/src/app/pages/AddEditNodePage/RequiredDimensionsSelect.jsx +54 -0
  88. package/src/app/pages/AddEditNodePage/TagsField.jsx +47 -0
  89. package/src/app/pages/AddEditNodePage/UpstreamNodeField.jsx +49 -0
  90. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +110 -0
  91. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +291 -0
  92. package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +75 -0
  93. package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +31 -0
  94. package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
  95. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +54 -0
  96. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +3 -0
  97. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +3 -0
  98. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +224 -0
  99. package/src/app/pages/AddEditNodePage/index.jsx +545 -0
  100. package/src/app/pages/AddEditTagPage/Loadable.jsx +16 -0
  101. package/src/app/pages/AddEditTagPage/__tests__/AddEditTagPage.test.jsx +107 -0
  102. package/src/app/pages/AddEditTagPage/index.jsx +132 -0
  103. package/src/app/pages/CubeBuilderPage/DimensionsSelect.jsx +152 -0
  104. package/src/app/pages/CubeBuilderPage/Loadable.jsx +16 -0
  105. package/src/app/pages/CubeBuilderPage/MetricsSelect.jsx +75 -0
  106. package/src/app/pages/CubeBuilderPage/__tests__/index.test.jsx +373 -0
  107. package/src/app/pages/CubeBuilderPage/index.jsx +291 -0
  108. package/src/app/pages/LoginPage/LoginForm.jsx +124 -0
  109. package/src/app/pages/LoginPage/SignupForm.jsx +156 -0
  110. package/src/app/pages/LoginPage/__tests__/index.test.jsx +97 -0
  111. package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
  112. package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
  113. package/src/app/pages/LoginPage/index.jsx +17 -0
  114. package/src/app/pages/NamespacePage/AddNamespacePopover.jsx +85 -0
  115. package/src/app/pages/NamespacePage/Explorer.jsx +232 -0
  116. package/src/app/pages/NamespacePage/FieldControl.jsx +21 -0
  117. package/src/app/pages/NamespacePage/NodeModeSelect.jsx +27 -0
  118. package/src/app/pages/NamespacePage/NodeTypeSelect.jsx +30 -0
  119. package/src/app/pages/NamespacePage/TagSelect.jsx +44 -0
  120. package/src/app/pages/NamespacePage/UserSelect.jsx +47 -0
  121. package/src/app/pages/NamespacePage/__tests__/AddNamespacePopover.test.jsx +283 -0
  122. package/src/app/pages/NamespacePage/__tests__/index.test.jsx +331 -0
  123. package/src/app/pages/NamespacePage/index.jsx +356 -42
  124. package/src/app/pages/NodePage/AddBackfillPopover.jsx +165 -0
  125. package/src/app/pages/NodePage/AddComplexDimensionLinkPopover.jsx +367 -0
  126. package/src/app/pages/NodePage/AddMaterializationPopover.jsx +222 -0
  127. package/src/app/pages/NodePage/AvailabilityStateBlock.jsx +67 -0
  128. package/src/app/pages/NodePage/ClientCodePopover.jsx +94 -0
  129. package/src/app/pages/NodePage/DimensionFilter.jsx +86 -0
  130. package/src/app/pages/NodePage/EditColumnDescriptionPopover.jsx +116 -0
  131. package/src/app/pages/NodePage/EditColumnPopover.jsx +116 -0
  132. package/src/app/pages/NodePage/LinkDimensionPopover.jsx +164 -0
  133. package/src/app/pages/NodePage/ManageDimensionLinksDialog.jsx +526 -0
  134. package/src/app/pages/NodePage/MaterializationConfigField.jsx +60 -0
  135. package/src/app/pages/NodePage/NodeColumnTab.jsx +421 -30
  136. package/src/app/pages/NodePage/NodeDependenciesTab.jsx +153 -0
  137. package/src/app/pages/NodePage/NodeGraphTab.jsx +119 -148
  138. package/src/app/pages/NodePage/NodeHistory.jsx +236 -0
  139. package/src/app/pages/NodePage/NodeInfoTab.jsx +346 -49
  140. package/src/app/pages/NodePage/NodeLineageTab.jsx +84 -0
  141. package/src/app/pages/NodePage/NodeMaterializationTab.jsx +585 -0
  142. package/src/app/pages/NodePage/NodeRevisionMaterializationTab.jsx +58 -0
  143. package/src/app/pages/NodePage/NodeStatus.jsx +100 -31
  144. package/src/app/pages/NodePage/NodeValidateTab.jsx +367 -0
  145. package/src/app/pages/NodePage/NodesWithDimension.jsx +42 -0
  146. package/src/app/pages/NodePage/NotebookDownload.jsx +36 -0
  147. package/src/app/pages/NodePage/PartitionColumnPopover.jsx +151 -0
  148. package/src/app/pages/NodePage/PartitionValueForm.jsx +60 -0
  149. package/src/app/pages/NodePage/RevisionDiff.jsx +209 -0
  150. package/src/app/pages/NodePage/WatchNodeButton.jsx +226 -0
  151. package/src/app/pages/NodePage/__tests__/AddBackfillPopover.test.jsx +56 -0
  152. package/src/app/pages/NodePage/__tests__/AddComplexDimensionLinkPopover.test.jsx +459 -0
  153. package/src/app/pages/NodePage/__tests__/AddMaterializationPopover.test.jsx +87 -0
  154. package/src/app/pages/NodePage/__tests__/DimensionFilter.test.jsx +74 -0
  155. package/src/app/pages/NodePage/__tests__/EditColumnDescriptionPopover.test.jsx +149 -0
  156. package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +144 -0
  157. package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +132 -0
  158. package/src/app/pages/NodePage/__tests__/ManageDimensionLinksDialog.test.jsx +390 -0
  159. package/src/app/pages/NodePage/__tests__/NodeColumnTab.test.jsx +166 -0
  160. package/src/app/pages/NodePage/__tests__/NodeDependenciesTab.test.jsx +151 -0
  161. package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +595 -0
  162. package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +58 -0
  163. package/src/app/pages/NodePage/__tests__/NodeMaterializationTab.test.jsx +190 -0
  164. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +882 -0
  165. package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
  166. package/src/app/pages/NodePage/__tests__/RevisionDiff.test.jsx +164 -0
  167. package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +19 -0
  168. package/src/app/pages/NodePage/index.jsx +190 -44
  169. package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
  170. package/src/app/pages/NotificationsPage/Loadable.jsx +6 -0
  171. package/src/app/pages/NotificationsPage/__tests__/index.test.jsx +287 -0
  172. package/src/app/pages/NotificationsPage/index.jsx +136 -0
  173. package/src/app/pages/OverviewPage/ByStatusPanel.jsx +69 -0
  174. package/src/app/pages/OverviewPage/DimensionNodeUsagePanel.jsx +48 -0
  175. package/src/app/pages/OverviewPage/GovernanceWarningsPanel.jsx +107 -0
  176. package/src/app/pages/OverviewPage/Loadable.jsx +16 -0
  177. package/src/app/pages/OverviewPage/NodesByTypePanel.jsx +63 -0
  178. package/src/app/pages/OverviewPage/OverviewPanel.jsx +94 -0
  179. package/src/app/pages/OverviewPage/TrendsPanel.jsx +66 -0
  180. package/src/app/pages/OverviewPage/__tests__/ByStatusPanel.test.jsx +36 -0
  181. package/src/app/pages/OverviewPage/__tests__/DimensionNodeUsagePanel.test.jsx +76 -0
  182. package/src/app/pages/OverviewPage/__tests__/GovernanceWarningsPanel.test.jsx +77 -0
  183. package/src/app/pages/OverviewPage/__tests__/NodesByTypePanel.test.jsx +86 -0
  184. package/src/app/pages/OverviewPage/__tests__/OverviewPanel.test.jsx +78 -0
  185. package/src/app/pages/OverviewPage/__tests__/TrendsPanel.test.jsx +120 -0
  186. package/src/app/pages/OverviewPage/__tests__/index.test.jsx +54 -0
  187. package/src/app/pages/OverviewPage/index.jsx +22 -0
  188. package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
  189. package/src/app/pages/RegisterTablePage/__tests__/RegisterTablePage.test.jsx +112 -0
  190. package/src/app/pages/RegisterTablePage/__tests__/__snapshots__/RegisterTablePage.test.jsx.snap +38 -0
  191. package/src/app/pages/RegisterTablePage/index.jsx +142 -0
  192. package/src/app/pages/Root/__tests__/index.test.jsx +44 -0
  193. package/src/app/pages/Root/index.tsx +92 -10
  194. package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
  195. package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
  196. package/src/app/pages/SQLBuilderPage/index.jsx +390 -0
  197. package/src/app/pages/SettingsPage/CreateServiceAccountModal.jsx +152 -0
  198. package/src/app/pages/SettingsPage/Loadable.jsx +16 -0
  199. package/src/app/pages/SettingsPage/NotificationSubscriptionsSection.jsx +189 -0
  200. package/src/app/pages/SettingsPage/ProfileSection.jsx +41 -0
  201. package/src/app/pages/SettingsPage/ServiceAccountsSection.jsx +95 -0
  202. package/src/app/pages/SettingsPage/__tests__/CreateServiceAccountModal.test.jsx +318 -0
  203. package/src/app/pages/SettingsPage/__tests__/NotificationSubscriptionsSection.test.jsx +233 -0
  204. package/src/app/pages/SettingsPage/__tests__/ProfileSection.test.jsx +65 -0
  205. package/src/app/pages/SettingsPage/__tests__/ServiceAccountsSection.test.jsx +150 -0
  206. package/src/app/pages/SettingsPage/__tests__/index.test.jsx +184 -0
  207. package/src/app/pages/SettingsPage/index.jsx +148 -0
  208. package/src/app/pages/TagPage/Loadable.jsx +16 -0
  209. package/src/app/pages/TagPage/__tests__/TagPage.test.jsx +70 -0
  210. package/src/app/pages/TagPage/index.jsx +79 -0
  211. package/src/app/services/DJService.js +1444 -21
  212. package/src/app/services/__tests__/DJService.test.jsx +2118 -0
  213. package/src/app/utils/__tests__/date.test.js +198 -0
  214. package/src/app/utils/date.js +65 -0
  215. package/src/index.tsx +1 -0
  216. package/src/mocks/mockNodes.jsx +1477 -0
  217. package/src/setupTests.ts +31 -1
  218. package/src/styles/dag.css +117 -5
  219. package/src/styles/index.css +1028 -31
  220. package/src/styles/loading.css +34 -0
  221. package/src/styles/login.css +81 -0
  222. package/src/styles/nav-bar.css +274 -0
  223. package/src/styles/node-creation.scss +276 -0
  224. package/src/styles/node-list.css +4 -0
  225. package/src/styles/overview.css +72 -0
  226. package/src/styles/settings.css +787 -0
  227. package/src/styles/sorted-table.css +15 -0
  228. package/src/styles/styles.scss +44 -0
  229. package/src/styles/styles.scss.d.ts +9 -0
  230. package/src/utils/form.jsx +23 -0
  231. package/webpack.config.js +17 -6
  232. package/.babelrc +0 -4
  233. package/.env.local +0 -4
  234. package/.env.production +0 -1
  235. package/.github/pull_request_template.md +0 -11
  236. package/.github/workflows/ci.yml +0 -33
  237. package/.vscode/extensions.json +0 -7
  238. package/.vscode/launch.json +0 -15
  239. package/.vscode/settings.json +0 -25
  240. package/Dockerfile +0 -7
  241. package/src/app/pages/ListNamespacesPage/Loadable.jsx +0 -14
  242. package/src/app/pages/ListNamespacesPage/index.jsx +0 -62
  243. package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +0 -45
  244. package/src/app/pages/NamespacePage/__tests__/index.test.tsx +0 -14
@@ -0,0 +1,175 @@
1
+ import React from 'react';
2
+ import { render, waitFor, screen } from '@testing-library/react';
3
+ import NodesWithDimension from '../NodesWithDimension';
4
+
5
+ describe('<NodesWithDimension />', () => {
6
+ const mockDjClient = {
7
+ nodesWithDimension: jest.fn(),
8
+ };
9
+
10
+ const mockNodesWithDimension = [
11
+ {
12
+ node_revision_id: 2,
13
+ node_id: 2,
14
+ type: 'source',
15
+ name: 'default.repair_order_details',
16
+ display_name: 'Default: Repair Order Details',
17
+ version: 'v1.0',
18
+ status: 'valid',
19
+ mode: 'published',
20
+ catalog: {
21
+ id: 1,
22
+ uuid: '0fc18295-e1a2-4c3c-b72a-894725c12488',
23
+ created_at: '2023-08-21T16:48:51.146121+00:00',
24
+ updated_at: '2023-08-21T16:48:51.146122+00:00',
25
+ extra_params: {},
26
+ name: 'warehouse',
27
+ },
28
+ schema_: 'roads',
29
+ table: 'repair_order_details',
30
+ description: 'Details on repair orders',
31
+ query: null,
32
+ availability: null,
33
+ columns: [
34
+ {
35
+ name: 'repair_order_id',
36
+ type: 'int',
37
+ attributes: [],
38
+ dimension: {
39
+ name: 'default.repair_order',
40
+ },
41
+ },
42
+ {
43
+ name: 'repair_type_id',
44
+ type: 'int',
45
+ attributes: [],
46
+ dimension: null,
47
+ },
48
+ {
49
+ name: 'price',
50
+ type: 'float',
51
+ attributes: [],
52
+ dimension: null,
53
+ },
54
+ {
55
+ name: 'quantity',
56
+ type: 'int',
57
+ attributes: [],
58
+ dimension: null,
59
+ },
60
+ {
61
+ name: 'discount',
62
+ type: 'float',
63
+ attributes: [],
64
+ dimension: null,
65
+ },
66
+ ],
67
+ updated_at: '2023-08-21T16:48:52.981201+00:00',
68
+ materializations: [],
69
+ parents: [],
70
+ },
71
+ {
72
+ node_revision_id: 1,
73
+ node_id: 1,
74
+ type: 'source',
75
+ name: 'default.repair_orders',
76
+ display_name: 'Default: Repair Orders',
77
+ version: 'v1.0',
78
+ status: 'valid',
79
+ mode: 'published',
80
+ catalog: {
81
+ id: 1,
82
+ uuid: '0fc18295-e1a2-4c3c-b72a-894725c12488',
83
+ created_at: '2023-08-21T16:48:51.146121+00:00',
84
+ updated_at: '2023-08-21T16:48:51.146122+00:00',
85
+ extra_params: {},
86
+ name: 'warehouse',
87
+ },
88
+ schema_: 'roads',
89
+ table: 'repair_orders',
90
+ description: 'Repair orders',
91
+ query: null,
92
+ availability: null,
93
+ columns: [
94
+ {
95
+ name: 'repair_order_id',
96
+ type: 'int',
97
+ attributes: [],
98
+ dimension: {
99
+ name: 'default.repair_order',
100
+ },
101
+ },
102
+ {
103
+ name: 'municipality_id',
104
+ type: 'string',
105
+ attributes: [],
106
+ dimension: null,
107
+ },
108
+ {
109
+ name: 'hard_hat_id',
110
+ type: 'int',
111
+ attributes: [],
112
+ dimension: null,
113
+ },
114
+ {
115
+ name: 'order_date',
116
+ type: 'date',
117
+ attributes: [],
118
+ dimension: null,
119
+ },
120
+ {
121
+ name: 'required_date',
122
+ type: 'date',
123
+ attributes: [],
124
+ dimension: null,
125
+ },
126
+ {
127
+ name: 'dispatched_date',
128
+ type: 'date',
129
+ attributes: [],
130
+ dimension: null,
131
+ },
132
+ {
133
+ name: 'dispatcher_id',
134
+ type: 'int',
135
+ attributes: [],
136
+ dimension: null,
137
+ },
138
+ ],
139
+ updated_at: '2023-08-21T16:48:52.880498+00:00',
140
+ materializations: [],
141
+ parents: [],
142
+ },
143
+ ];
144
+
145
+ const defaultProps = {
146
+ node: {
147
+ name: 'TestNode',
148
+ },
149
+ djClient: mockDjClient,
150
+ };
151
+
152
+ beforeEach(() => {
153
+ // Reset the mocks before each test
154
+ mockDjClient.nodesWithDimension.mockReset();
155
+ });
156
+
157
+ it('renders nodes with dimensions', async () => {
158
+ mockDjClient.nodesWithDimension.mockReturnValue(mockNodesWithDimension);
159
+ render(<NodesWithDimension {...defaultProps} />);
160
+ await waitFor(() => {
161
+ // calls nodesWithDimension with the correct node name
162
+ expect(mockDjClient.nodesWithDimension).toHaveBeenCalledWith(
163
+ defaultProps.node.name,
164
+ );
165
+ for (const node of mockNodesWithDimension) {
166
+ // renders nodes based on nodesWithDimension data
167
+ expect(screen.getByText(node.display_name)).toBeInTheDocument();
168
+
169
+ // renders links to the correct URLs
170
+ const link = screen.getByText(node.display_name).closest('a');
171
+ expect(link).toHaveAttribute('href', `/nodes/${node.name}`);
172
+ }
173
+ });
174
+ });
175
+ });
@@ -0,0 +1,164 @@
1
+ import React from 'react';
2
+ import { render, waitFor, screen } from '@testing-library/react';
3
+ import RevisionDiff from '../RevisionDiff';
4
+ import DJClientContext from '../../../providers/djclient';
5
+ import { NodePage } from '../Loadable';
6
+ import { MemoryRouter, Route, Routes } from 'react-router-dom';
7
+
8
+ describe('<RevisionDiff />', () => {
9
+ const mockDjClient = {
10
+ DataJunctionAPI: {
11
+ revisions: jest.fn(),
12
+ },
13
+ };
14
+
15
+ const mockNodesWithDimension = [
16
+ {
17
+ node_revision_id: 1,
18
+ node_id: 1,
19
+ type: 'dimension',
20
+ name: 'default.repair_order',
21
+ display_name: 'Repair Orders',
22
+ version: 'v1.0',
23
+ status: 'valid',
24
+ mode: 'published',
25
+ catalog: {
26
+ id: 1,
27
+ uuid: '0fc18295-e1a2-4c3c-b72a-894725c12488',
28
+ created_at: '2023-08-21T16:48:51.146121+00:00',
29
+ updated_at: '2023-08-21T16:48:51.146122+00:00',
30
+ extra_params: {},
31
+ name: 'warehouse',
32
+ },
33
+ description: 'Repair order dimension',
34
+ query:
35
+ 'SELECT repair_order_id, municipality_id, hard_hat_id, order_date, ' +
36
+ 'dispatcher_id FROM default.repair_orders',
37
+ availability: null,
38
+ columns: [
39
+ {
40
+ name: 'repair_order_id',
41
+ type: 'int',
42
+ attributes: [],
43
+ dimension: {
44
+ name: 'default.repair_order',
45
+ },
46
+ },
47
+ {
48
+ name: 'municipality_id',
49
+ type: 'int',
50
+ attributes: [],
51
+ dimension: null,
52
+ },
53
+ {
54
+ name: 'hard_hat_id',
55
+ type: 'int',
56
+ attributes: [],
57
+ dimension: null,
58
+ },
59
+ {
60
+ name: 'order_date',
61
+ type: 'date',
62
+ attributes: [],
63
+ dimension: null,
64
+ },
65
+ {
66
+ name: 'dispatcher_id',
67
+ type: 'int',
68
+ attributes: [],
69
+ dimension: null,
70
+ },
71
+ ],
72
+ updated_at: '2023-08-21T16:48:52.981201+00:00',
73
+ materializations: [],
74
+ parents: [],
75
+ },
76
+ {
77
+ node_revision_id: 2,
78
+ node_id: 2,
79
+ type: 'dimension',
80
+ name: 'default.repair_order',
81
+ display_name: 'Repair Orders',
82
+ version: 'v2.0',
83
+ status: 'valid',
84
+ mode: 'published',
85
+ catalog: {
86
+ id: 1,
87
+ uuid: '0fc18295-e1a2-4c3c-b72a-894725c12488',
88
+ created_at: '2023-08-21T16:48:51.146121+00:00',
89
+ updated_at: '2023-08-21T16:48:51.146122+00:00',
90
+ extra_params: {},
91
+ name: 'warehouse',
92
+ },
93
+ description: 'Repair order dimension',
94
+ query:
95
+ 'SELECT repair_order_id, municipality_id, hard_hat_id, ' +
96
+ 'dispatcher_id FROM default.repair_orders',
97
+ availability: null,
98
+ columns: [
99
+ {
100
+ name: 'repair_order_id',
101
+ type: 'int',
102
+ attributes: [],
103
+ dimension: {
104
+ name: 'default.repair_order',
105
+ },
106
+ },
107
+ {
108
+ name: 'municipality_id',
109
+ type: 'int',
110
+ attributes: [],
111
+ dimension: null,
112
+ },
113
+ {
114
+ name: 'hard_hat_id',
115
+ type: 'int',
116
+ attributes: [],
117
+ dimension: null,
118
+ },
119
+ {
120
+ name: 'dispatcher_id',
121
+ type: 'int',
122
+ attributes: [],
123
+ dimension: null,
124
+ },
125
+ ],
126
+ updated_at: '2023-08-21T16:48:52.981201+00:00',
127
+ materializations: [],
128
+ parents: [],
129
+ },
130
+ ];
131
+
132
+ beforeEach(() => {
133
+ // Reset the mocks before each test
134
+ mockDjClient.DataJunctionAPI.revisions.mockReset();
135
+ });
136
+
137
+ it('renders revision diff', async () => {
138
+ mockDjClient.DataJunctionAPI.revisions.mockReturnValue(
139
+ mockNodesWithDimension,
140
+ );
141
+ const element = (
142
+ <DJClientContext.Provider value={mockDjClient}>
143
+ <RevisionDiff />
144
+ </DJClientContext.Provider>
145
+ );
146
+ const { container } = render(
147
+ <MemoryRouter
148
+ initialEntries={['/nodes/default.repair_orders_cube/revisions/v2.0']}
149
+ >
150
+ <Routes>
151
+ <Route path="nodes/:name/revisions/:revision" element={element} />
152
+ </Routes>
153
+ </MemoryRouter>,
154
+ );
155
+ await waitFor(() => {
156
+ expect(mockDjClient.DataJunctionAPI.revisions).toHaveBeenCalledWith(
157
+ 'default.repair_orders_cube',
158
+ );
159
+
160
+ const diffViews = screen.getAllByRole('gridcell', 'DiffView');
161
+ diffViews.map(diffView => expect(diffView).toBeInTheDocument());
162
+ });
163
+ });
164
+ });
@@ -0,0 +1,19 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<NodePage /> renders the NodeInfo tab correctly for a metric node 1`] = `
4
+ HTMLCollection [
5
+ <code
6
+ class="language-sql"
7
+ style="white-space: pre;"
8
+ >
9
+ <span
10
+ class="hljs-built_in"
11
+ >
12
+ count
13
+ </span>
14
+ <span>
15
+ (repair_order_id)
16
+ </span>
17
+ </code>,
18
+ ]
19
+ `;
@@ -5,23 +5,40 @@ import Tab from '../../components/Tab';
5
5
  import NamespaceHeader from '../../components/NamespaceHeader';
6
6
  import NodeInfoTab from './NodeInfoTab';
7
7
  import NodeColumnTab from './NodeColumnTab';
8
- import NodeLineage from './NodeGraphTab';
8
+ import NodeGraphTab from './NodeGraphTab';
9
+ import NodeHistory from './NodeHistory';
10
+ import NotebookDownload from './NotebookDownload';
9
11
  import DJClientContext from '../../providers/djclient';
12
+ import NodeValidateTab from './NodeValidateTab';
13
+ import NodeMaterializationTab from './NodeMaterializationTab';
14
+ import ClientCodePopover from './ClientCodePopover';
15
+ import WatchButton from './WatchNodeButton';
16
+ import NodesWithDimension from './NodesWithDimension';
17
+ import NodeColumnLineage from './NodeLineageTab';
18
+ import EditIcon from '../../icons/EditIcon';
19
+ import AlertIcon from '../../icons/AlertIcon';
20
+ import NodeDependenciesTab from './NodeDependenciesTab';
21
+ import { useNavigate } from 'react-router-dom';
10
22
 
11
23
  export function NodePage() {
12
24
  const djClient = useContext(DJClientContext).DataJunctionAPI;
25
+ const navigate = useNavigate();
26
+
27
+ const { name, tab } = useParams();
28
+
13
29
  const [state, setState] = useState({
14
- selectedTab: 0,
30
+ selectedTab: tab || 'info',
15
31
  });
16
32
 
17
33
  const [node, setNode] = useState();
18
34
 
19
35
  const onClickTab = id => () => {
36
+ navigate(`/nodes/${name}/${id}`);
20
37
  setState({ selectedTab: id });
21
38
  };
22
39
 
23
40
  const buildTabs = tab => {
24
- return (
41
+ return tab.display ? (
25
42
  <Tab
26
43
  key={tab.id}
27
44
  id={tab.id}
@@ -29,72 +46,201 @@ export function NodePage() {
29
46
  onClick={onClickTab(tab.id)}
30
47
  selectedTab={state.selectedTab}
31
48
  />
32
- );
49
+ ) : null;
33
50
  };
34
51
 
35
- const { name } = useParams();
36
-
37
52
  useEffect(() => {
38
53
  const fetchData = async () => {
39
54
  const data = await djClient.node(name);
55
+ data.createNodeClientCode = await djClient.clientCode(name);
56
+ if (data.type === 'metric') {
57
+ const metric = await djClient.getMetric(name);
58
+ data.metric_metadata = metric.current.metricMetadata;
59
+ data.required_dimensions = metric.current.requiredDimensions;
60
+ data.upstream_node = metric.current.parents[0].name;
61
+ data.expression = metric.current.metricMetadata.expression;
62
+ data.incompatible_druid_functions =
63
+ metric.current.metricMetadata.incompatibleDruidFunctions;
64
+ }
65
+ if (data.type === 'cube') {
66
+ const cube = await djClient.cube(name);
67
+ data.cube_elements = cube.cube_elements;
68
+ }
40
69
  setNode(data);
41
70
  };
42
71
  fetchData().catch(console.error);
43
72
  }, [djClient, name]);
44
73
 
45
- const TabsJson = [
46
- {
47
- id: 0,
48
- name: 'Info',
49
- },
50
- {
51
- id: 1,
52
- name: 'Columns',
53
- },
54
- {
55
- id: 2,
56
- name: 'Graph',
57
- },
58
- ];
59
- //
60
- //
74
+ const tabsList = node => {
75
+ return [
76
+ {
77
+ id: 'info',
78
+ name: 'Info',
79
+ display: true,
80
+ },
81
+ {
82
+ id: 'columns',
83
+ name: 'Columns',
84
+ display: true,
85
+ },
86
+ {
87
+ id: 'graph',
88
+ name: 'Graph',
89
+ display: true,
90
+ },
91
+ {
92
+ id: 'history',
93
+ name: 'History',
94
+ display: true,
95
+ },
96
+ {
97
+ id: 'validate',
98
+ name: '► Validate',
99
+ display: node?.type !== 'source',
100
+ },
101
+ {
102
+ id: 'materializations',
103
+ name: 'Materializations',
104
+ display: node?.type !== 'source',
105
+ },
106
+ {
107
+ id: 'linked',
108
+ name: 'Linked Nodes',
109
+ display: node?.type === 'dimension',
110
+ },
111
+ {
112
+ id: 'lineage',
113
+ name: 'Lineage',
114
+ display: node?.type === 'metric',
115
+ },
116
+ {
117
+ id: 'dependencies',
118
+ name: 'Dependencies',
119
+ display: node?.type !== 'cube',
120
+ },
121
+ ];
122
+ };
61
123
  let tabToDisplay = null;
124
+
62
125
  switch (state.selectedTab) {
63
- case 0:
64
- tabToDisplay = node ? <NodeInfoTab node={node} /> : '';
126
+ case 'info':
127
+ tabToDisplay =
128
+ node && node.message === undefined ? <NodeInfoTab node={node} /> : '';
129
+ break;
130
+ case 'columns':
131
+ tabToDisplay = <NodeColumnTab node={node} djClient={djClient} />;
132
+ break;
133
+ case 'graph':
134
+ tabToDisplay = <NodeGraphTab djNode={node} djClient={djClient} />;
135
+ break;
136
+ case 'history':
137
+ tabToDisplay = <NodeHistory node={node} djClient={djClient} />;
138
+ break;
139
+ case 'validate':
140
+ tabToDisplay = <NodeValidateTab node={node} djClient={djClient} />;
65
141
  break;
66
- case 1:
67
- tabToDisplay = <NodeColumnTab node={node} />;
142
+ case 'materializations':
143
+ tabToDisplay = <NodeMaterializationTab node={node} djClient={djClient} />;
68
144
  break;
69
- case 2:
70
- tabToDisplay = <NodeLineage djNode={node} djClient={djClient} />;
145
+ case 'linked':
146
+ tabToDisplay = <NodesWithDimension node={node} djClient={djClient} />;
147
+ break;
148
+ case 'lineage':
149
+ tabToDisplay = <NodeColumnLineage djNode={node} djClient={djClient} />;
150
+ break;
151
+ case 'dependencies':
152
+ tabToDisplay = <NodeDependenciesTab node={node} djClient={djClient} />;
71
153
  break;
72
154
  default:
155
+ /* istanbul ignore next */
73
156
  tabToDisplay = <NodeInfoTab node={node} />;
74
157
  }
75
158
 
159
+ const NodeButtons = () => {
160
+ return (
161
+ <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
162
+ <button
163
+ className="button-3"
164
+ onClick={() => navigate(`/nodes/${node?.name}/edit`)}
165
+ >
166
+ <EditIcon /> Edit
167
+ </button>
168
+
169
+ <WatchButton node={node} />
170
+
171
+ <ClientCodePopover code={node?.createNodeClientCode} />
172
+ {node?.type === 'cube' && <NotebookDownload node={node} />}
173
+ </div>
174
+ );
175
+ };
176
+
76
177
  // @ts-ignore
77
178
  return (
78
179
  <div className="node__header">
79
180
  <NamespaceHeader namespace={name.split('.').slice(0, -1).join('.')} />
80
181
  <div className="card">
81
- <div className="card-header">
82
- <h3 className="card-title align-items-start flex-column">
83
- <span className="card-label fw-bold text-gray-800">
84
- {node?.display_name}
85
- </span>
86
- </h3>
87
- <span
88
- className="fs-6 fw-semibold text-gray-400"
89
- style={{ marginTop: '-4rem' }}
90
- >
91
- Updated {new Date(node?.updated_at).toDateString()}
92
- </span>
93
- <div className="align-items-center row">
94
- {TabsJson.map(buildTabs)}
182
+ {node?.message === undefined ? (
183
+ <div className="card-header" style={{}}>
184
+ <div
185
+ style={{
186
+ display: 'flex',
187
+ flexDirection: 'row',
188
+ justifyContent: 'space-between',
189
+ }}
190
+ >
191
+ <h3
192
+ className="card-title align-items-start flex-column"
193
+ style={{ display: 'inline-block' }}
194
+ >
195
+ <span
196
+ className="card-label fw-bold text-gray-800"
197
+ role="dialog"
198
+ aria-hidden="false"
199
+ aria-label="DisplayName"
200
+ >
201
+ {node?.display_name}{' '}
202
+ <span
203
+ className={'node_type__' + node?.type + ' badge node_type'}
204
+ role="dialog"
205
+ aria-hidden="false"
206
+ aria-label="NodeType"
207
+ >
208
+ {node?.type}
209
+ </span>
210
+ </span>
211
+ </h3>
212
+ <NodeButtons />
213
+ </div>
214
+ <div>
215
+ <a
216
+ href={'/nodes/' + node?.name}
217
+ className="link-table"
218
+ role="dialog"
219
+ aria-hidden="false"
220
+ aria-label="NodeName"
221
+ >
222
+ {node?.name}
223
+ </a>
224
+ <span
225
+ className="rounded-pill badge bg-secondary-soft"
226
+ style={{ marginLeft: '0.5rem' }}
227
+ >
228
+ {node?.version}
229
+ </span>
230
+ </div>
231
+ <div className="align-items-center row">
232
+ {tabsList(node).map(buildTabs)}
233
+ </div>
234
+ {tabToDisplay}
235
+ </div>
236
+ ) : node?.message !== undefined ? (
237
+ <div className="message alert" style={{ margin: '20px' }}>
238
+ <AlertIcon />
239
+ Node `{name}` does not exist!
95
240
  </div>
96
- {tabToDisplay}
97
- </div>
241
+ ) : (
242
+ ''
243
+ )}
98
244
  </div>
99
245
  </div>
100
246
  );
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import { NotFoundPage } from '../index';
4
+ import { HelmetProvider } from 'react-helmet-async';
5
+
6
+ describe('<NotFoundPage />', () => {
7
+ it('displays the correct 404 message ', () => {
8
+ const { getByText } = render(
9
+ <HelmetProvider>
10
+ <NotFoundPage />
11
+ </HelmetProvider>,
12
+ );
13
+
14
+ expect(getByText('Page not found.')).toBeInTheDocument();
15
+ });
16
+ });
@@ -0,0 +1,6 @@
1
+ import { lazyLoad } from '../../../utils/loadable';
2
+
3
+ export const NotificationsPage = lazyLoad(
4
+ () => import('./index'),
5
+ module => module.NotificationsPage,
6
+ );