datajunction-ui 0.0.1-rc.9 → 0.0.2-3.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 (238) hide show
  1. package/.env +2 -0
  2. package/.prettierignore +3 -1
  3. package/Makefile +9 -0
  4. package/dj-logo.svg +10 -0
  5. package/package.json +53 -14
  6. package/public/favicon.ico +0 -0
  7. package/public/index.html +1 -1
  8. package/src/__tests__/reportWebVitals.test.jsx +44 -0
  9. package/src/app/__tests__/__snapshots__/index.test.tsx.snap +5 -109
  10. package/src/app/components/AddNodeDropdown.jsx +44 -0
  11. package/src/app/components/ListGroupItem.jsx +9 -1
  12. package/src/app/components/NamespaceHeader.jsx +4 -13
  13. package/src/app/components/NodeListActions.jsx +69 -0
  14. package/src/app/components/NodeMaterializationDelete.jsx +90 -0
  15. package/src/app/components/NotificationBell.tsx +229 -0
  16. package/src/app/components/QueryInfo.jsx +172 -0
  17. package/src/app/components/Search.jsx +94 -0
  18. package/src/app/components/Tab.jsx +8 -1
  19. package/src/app/components/ToggleSwitch.jsx +20 -0
  20. package/src/app/components/UserMenu.tsx +92 -0
  21. package/src/app/components/__tests__/NodeListActions.test.jsx +94 -0
  22. package/src/app/components/__tests__/NodeMaterializationDelete.test.jsx +263 -0
  23. package/src/app/components/__tests__/NotificationBell.test.tsx +313 -0
  24. package/src/app/components/__tests__/QueryInfo.test.jsx +183 -0
  25. package/src/app/components/__tests__/Search.test.jsx +307 -0
  26. package/src/app/components/__tests__/Tab.test.jsx +27 -0
  27. package/src/app/components/__tests__/ToggleSwitch.test.jsx +43 -0
  28. package/src/app/components/__tests__/UserMenu.test.tsx +248 -0
  29. package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +8 -3
  30. package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +2 -18
  31. package/src/app/components/djgraph/Collapse.jsx +47 -0
  32. package/src/app/components/djgraph/DJNode.jsx +61 -83
  33. package/src/app/components/djgraph/DJNodeColumns.jsx +75 -0
  34. package/src/app/components/djgraph/DJNodeDimensions.jsx +75 -0
  35. package/src/app/components/djgraph/LayoutFlow.jsx +106 -0
  36. package/src/app/components/djgraph/__tests__/Collapse.test.jsx +51 -0
  37. package/src/app/components/djgraph/__tests__/DJNodeColumns.test.jsx +83 -0
  38. package/src/app/components/djgraph/__tests__/DJNodeDimensions.test.jsx +118 -0
  39. package/src/app/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +84 -40
  40. package/src/app/components/forms/Action.jsx +8 -0
  41. package/src/app/components/forms/NodeNameField.jsx +64 -0
  42. package/src/app/components/search.css +17 -0
  43. package/src/app/constants.js +2 -0
  44. package/src/app/icons/AddItemIcon.jsx +16 -0
  45. package/src/app/icons/AlertIcon.jsx +33 -0
  46. package/src/app/icons/CollapsedIcon.jsx +15 -0
  47. package/src/app/icons/CommitIcon.jsx +45 -0
  48. package/src/app/icons/DJLogo.jsx +36 -0
  49. package/src/app/icons/DeleteIcon.jsx +21 -0
  50. package/src/app/icons/DiffIcon.jsx +63 -0
  51. package/src/app/icons/EditIcon.jsx +18 -0
  52. package/src/app/icons/ExpandedIcon.jsx +15 -0
  53. package/src/app/icons/EyeIcon.jsx +20 -0
  54. package/src/app/icons/FilterIcon.jsx +7 -0
  55. package/src/app/icons/HorizontalHierarchyIcon.jsx +15 -0
  56. package/src/app/icons/InvalidIcon.jsx +16 -0
  57. package/src/app/icons/JupyterExportIcon.jsx +25 -0
  58. package/src/app/icons/LoadingIcon.jsx +14 -0
  59. package/src/app/icons/NodeIcon.jsx +49 -0
  60. package/src/app/icons/NotificationIcon.jsx +27 -0
  61. package/src/app/icons/PythonIcon.jsx +14 -0
  62. package/src/app/icons/SettingsIcon.jsx +28 -0
  63. package/src/app/icons/TableIcon.jsx +14 -0
  64. package/src/app/icons/ValidIcon.jsx +16 -0
  65. package/src/app/index.tsx +138 -38
  66. package/src/app/pages/AddEditNodePage/AlertMessage.jsx +10 -0
  67. package/src/app/pages/AddEditNodePage/ColumnsSelect.jsx +84 -0
  68. package/src/app/pages/AddEditNodePage/CustomMetadataField.jsx +144 -0
  69. package/src/app/pages/AddEditNodePage/DescriptionField.jsx +17 -0
  70. package/src/app/pages/AddEditNodePage/DisplayNameField.jsx +16 -0
  71. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +64 -0
  72. package/src/app/pages/AddEditNodePage/FullNameField.jsx +38 -0
  73. package/src/app/pages/AddEditNodePage/Loadable.jsx +20 -0
  74. package/src/app/pages/AddEditNodePage/MetricMetadataFields.jsx +75 -0
  75. package/src/app/pages/AddEditNodePage/MetricQueryField.jsx +71 -0
  76. package/src/app/pages/AddEditNodePage/NamespaceField.jsx +40 -0
  77. package/src/app/pages/AddEditNodePage/NodeModeField.jsx +14 -0
  78. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +94 -0
  79. package/src/app/pages/AddEditNodePage/OwnersField.jsx +53 -0
  80. package/src/app/pages/AddEditNodePage/RequiredDimensionsSelect.jsx +54 -0
  81. package/src/app/pages/AddEditNodePage/TagsField.jsx +47 -0
  82. package/src/app/pages/AddEditNodePage/UpstreamNodeField.jsx +49 -0
  83. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +110 -0
  84. package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +291 -0
  85. package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +75 -0
  86. package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +31 -0
  87. package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
  88. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +54 -0
  89. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +3 -0
  90. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +3 -0
  91. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +224 -0
  92. package/src/app/pages/AddEditNodePage/index.jsx +545 -0
  93. package/src/app/pages/AddEditTagPage/Loadable.jsx +16 -0
  94. package/src/app/pages/AddEditTagPage/__tests__/AddEditTagPage.test.jsx +107 -0
  95. package/src/app/pages/AddEditTagPage/index.jsx +132 -0
  96. package/src/app/pages/CubeBuilderPage/DimensionsSelect.jsx +152 -0
  97. package/src/app/pages/CubeBuilderPage/Loadable.jsx +16 -0
  98. package/src/app/pages/CubeBuilderPage/MetricsSelect.jsx +75 -0
  99. package/src/app/pages/CubeBuilderPage/__tests__/index.test.jsx +373 -0
  100. package/src/app/pages/CubeBuilderPage/index.jsx +291 -0
  101. package/src/app/pages/LoginPage/LoginForm.jsx +124 -0
  102. package/src/app/pages/LoginPage/SignupForm.jsx +156 -0
  103. package/src/app/pages/LoginPage/__tests__/index.test.jsx +97 -0
  104. package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
  105. package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
  106. package/src/app/pages/LoginPage/index.jsx +17 -0
  107. package/src/app/pages/NamespacePage/AddNamespacePopover.jsx +85 -0
  108. package/src/app/pages/NamespacePage/Explorer.jsx +232 -0
  109. package/src/app/pages/NamespacePage/FieldControl.jsx +21 -0
  110. package/src/app/pages/NamespacePage/NodeModeSelect.jsx +27 -0
  111. package/src/app/pages/NamespacePage/NodeTypeSelect.jsx +30 -0
  112. package/src/app/pages/NamespacePage/TagSelect.jsx +44 -0
  113. package/src/app/pages/NamespacePage/UserSelect.jsx +47 -0
  114. package/src/app/pages/NamespacePage/__tests__/AddNamespacePopover.test.jsx +283 -0
  115. package/src/app/pages/NamespacePage/__tests__/index.test.jsx +331 -0
  116. package/src/app/pages/NamespacePage/index.jsx +354 -42
  117. package/src/app/pages/NodePage/AddBackfillPopover.jsx +165 -0
  118. package/src/app/pages/NodePage/AddComplexDimensionLinkPopover.jsx +367 -0
  119. package/src/app/pages/NodePage/AddMaterializationPopover.jsx +222 -0
  120. package/src/app/pages/NodePage/AvailabilityStateBlock.jsx +67 -0
  121. package/src/app/pages/NodePage/ClientCodePopover.jsx +116 -0
  122. package/src/app/pages/NodePage/DimensionFilter.jsx +86 -0
  123. package/src/app/pages/NodePage/EditColumnDescriptionPopover.jsx +116 -0
  124. package/src/app/pages/NodePage/EditColumnPopover.jsx +116 -0
  125. package/src/app/pages/NodePage/LinkDimensionPopover.jsx +164 -0
  126. package/src/app/pages/NodePage/ManageDimensionLinksDialog.jsx +526 -0
  127. package/src/app/pages/NodePage/MaterializationConfigField.jsx +60 -0
  128. package/src/app/pages/NodePage/NodeColumnTab.jsx +421 -30
  129. package/src/app/pages/NodePage/NodeDependenciesTab.jsx +155 -0
  130. package/src/app/pages/NodePage/NodeGraphTab.jsx +119 -148
  131. package/src/app/pages/NodePage/NodeHistory.jsx +236 -0
  132. package/src/app/pages/NodePage/NodeInfoTab.jsx +404 -49
  133. package/src/app/pages/NodePage/NodeLineageTab.jsx +84 -0
  134. package/src/app/pages/NodePage/NodeMaterializationTab.jsx +585 -0
  135. package/src/app/pages/NodePage/NodeRevisionMaterializationTab.jsx +58 -0
  136. package/src/app/pages/NodePage/NodeStatus.jsx +100 -31
  137. package/src/app/pages/NodePage/NodeValidateTab.jsx +367 -0
  138. package/src/app/pages/NodePage/NodesWithDimension.jsx +42 -0
  139. package/src/app/pages/NodePage/NotebookDownload.jsx +36 -0
  140. package/src/app/pages/NodePage/PartitionColumnPopover.jsx +151 -0
  141. package/src/app/pages/NodePage/PartitionValueForm.jsx +60 -0
  142. package/src/app/pages/NodePage/RevisionDiff.jsx +209 -0
  143. package/src/app/pages/NodePage/WatchNodeButton.jsx +226 -0
  144. package/src/app/pages/NodePage/__tests__/AddBackfillPopover.test.jsx +56 -0
  145. package/src/app/pages/NodePage/__tests__/AddComplexDimensionLinkPopover.test.jsx +459 -0
  146. package/src/app/pages/NodePage/__tests__/AddMaterializationPopover.test.jsx +87 -0
  147. package/src/app/pages/NodePage/__tests__/DimensionFilter.test.jsx +74 -0
  148. package/src/app/pages/NodePage/__tests__/EditColumnDescriptionPopover.test.jsx +149 -0
  149. package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +144 -0
  150. package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +132 -0
  151. package/src/app/pages/NodePage/__tests__/ManageDimensionLinksDialog.test.jsx +390 -0
  152. package/src/app/pages/NodePage/__tests__/NodeColumnTab.test.jsx +166 -0
  153. package/src/app/pages/NodePage/__tests__/NodeDependenciesTab.test.jsx +157 -0
  154. package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +595 -0
  155. package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +58 -0
  156. package/src/app/pages/NodePage/__tests__/NodeMaterializationTab.test.jsx +190 -0
  157. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +892 -0
  158. package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
  159. package/src/app/pages/NodePage/__tests__/RevisionDiff.test.jsx +164 -0
  160. package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +19 -0
  161. package/src/app/pages/NodePage/index.jsx +186 -45
  162. package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
  163. package/src/app/pages/NotificationsPage/Loadable.jsx +6 -0
  164. package/src/app/pages/NotificationsPage/__tests__/index.test.jsx +287 -0
  165. package/src/app/pages/NotificationsPage/index.jsx +136 -0
  166. package/src/app/pages/OverviewPage/ByStatusPanel.jsx +69 -0
  167. package/src/app/pages/OverviewPage/DimensionNodeUsagePanel.jsx +48 -0
  168. package/src/app/pages/OverviewPage/GovernanceWarningsPanel.jsx +107 -0
  169. package/src/app/pages/OverviewPage/Loadable.jsx +16 -0
  170. package/src/app/pages/OverviewPage/NodesByTypePanel.jsx +63 -0
  171. package/src/app/pages/OverviewPage/OverviewPanel.jsx +94 -0
  172. package/src/app/pages/OverviewPage/TrendsPanel.jsx +66 -0
  173. package/src/app/pages/OverviewPage/__tests__/ByStatusPanel.test.jsx +36 -0
  174. package/src/app/pages/OverviewPage/__tests__/DimensionNodeUsagePanel.test.jsx +76 -0
  175. package/src/app/pages/OverviewPage/__tests__/GovernanceWarningsPanel.test.jsx +77 -0
  176. package/src/app/pages/OverviewPage/__tests__/NodesByTypePanel.test.jsx +86 -0
  177. package/src/app/pages/OverviewPage/__tests__/OverviewPanel.test.jsx +78 -0
  178. package/src/app/pages/OverviewPage/__tests__/TrendsPanel.test.jsx +120 -0
  179. package/src/app/pages/OverviewPage/__tests__/index.test.jsx +54 -0
  180. package/src/app/pages/OverviewPage/index.jsx +22 -0
  181. package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
  182. package/src/app/pages/RegisterTablePage/__tests__/RegisterTablePage.test.jsx +112 -0
  183. package/src/app/pages/RegisterTablePage/__tests__/__snapshots__/RegisterTablePage.test.jsx.snap +38 -0
  184. package/src/app/pages/RegisterTablePage/index.jsx +142 -0
  185. package/src/app/pages/Root/__tests__/index.test.jsx +44 -0
  186. package/src/app/pages/Root/index.tsx +92 -10
  187. package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
  188. package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
  189. package/src/app/pages/SQLBuilderPage/index.jsx +390 -0
  190. package/src/app/pages/SettingsPage/CreateServiceAccountModal.jsx +152 -0
  191. package/src/app/pages/SettingsPage/Loadable.jsx +16 -0
  192. package/src/app/pages/SettingsPage/NotificationSubscriptionsSection.jsx +189 -0
  193. package/src/app/pages/SettingsPage/ProfileSection.jsx +41 -0
  194. package/src/app/pages/SettingsPage/ServiceAccountsSection.jsx +95 -0
  195. package/src/app/pages/SettingsPage/__tests__/CreateServiceAccountModal.test.jsx +318 -0
  196. package/src/app/pages/SettingsPage/__tests__/NotificationSubscriptionsSection.test.jsx +233 -0
  197. package/src/app/pages/SettingsPage/__tests__/ProfileSection.test.jsx +65 -0
  198. package/src/app/pages/SettingsPage/__tests__/ServiceAccountsSection.test.jsx +150 -0
  199. package/src/app/pages/SettingsPage/__tests__/index.test.jsx +187 -0
  200. package/src/app/pages/SettingsPage/index.jsx +148 -0
  201. package/src/app/pages/TagPage/Loadable.jsx +16 -0
  202. package/src/app/pages/TagPage/__tests__/TagPage.test.jsx +70 -0
  203. package/src/app/pages/TagPage/index.jsx +79 -0
  204. package/src/app/providers/UserProvider.tsx +78 -0
  205. package/src/app/services/DJService.js +1487 -21
  206. package/src/app/services/__tests__/DJService.test.jsx +2194 -0
  207. package/src/app/utils/__tests__/date.test.js +198 -0
  208. package/src/app/utils/date.js +65 -0
  209. package/src/index.tsx +1 -0
  210. package/src/mocks/mockNodes.jsx +1477 -0
  211. package/src/setupTests.ts +31 -1
  212. package/src/styles/dag.css +117 -5
  213. package/src/styles/index.css +1028 -31
  214. package/src/styles/loading.css +34 -0
  215. package/src/styles/login.css +81 -0
  216. package/src/styles/nav-bar.css +274 -0
  217. package/src/styles/node-creation.scss +276 -0
  218. package/src/styles/node-list.css +4 -0
  219. package/src/styles/overview.css +72 -0
  220. package/src/styles/settings.css +787 -0
  221. package/src/styles/sorted-table.css +15 -0
  222. package/src/styles/styles.scss +44 -0
  223. package/src/styles/styles.scss.d.ts +9 -0
  224. package/src/utils/form.jsx +23 -0
  225. package/webpack.config.js +20 -7
  226. package/.babelrc +0 -4
  227. package/.env.local +0 -4
  228. package/.env.production +0 -1
  229. package/.github/pull_request_template.md +0 -11
  230. package/.github/workflows/ci.yml +0 -33
  231. package/.vscode/extensions.json +0 -7
  232. package/.vscode/launch.json +0 -15
  233. package/.vscode/settings.json +0 -25
  234. package/Dockerfile +0 -7
  235. package/src/app/pages/ListNamespacesPage/Loadable.jsx +0 -14
  236. package/src/app/pages/ListNamespacesPage/index.jsx +0 -62
  237. package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +0 -45
  238. package/src/app/pages/NamespacePage/__tests__/index.test.tsx +0 -14
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Add or edit tags
3
+ */
4
+ import { ErrorMessage, Field, Form, Formik } from 'formik';
5
+
6
+ import NamespaceHeader from '../../components/NamespaceHeader';
7
+ import React, { useContext } from 'react';
8
+ import DJClientContext from '../../providers/djclient';
9
+ import 'styles/node-creation.scss';
10
+ import { displayMessageAfterSubmit } from '../../../utils/form';
11
+
12
+ export function AddEditTagPage() {
13
+ const djClient = useContext(DJClientContext).DataJunctionAPI;
14
+ const initialValues = {
15
+ name: '',
16
+ };
17
+
18
+ const validator = values => {
19
+ const errors = {};
20
+ if (!values.name) {
21
+ errors.name = 'Required';
22
+ }
23
+ return errors;
24
+ };
25
+
26
+ const handleSubmit = async (values, { setSubmitting, setStatus }) => {
27
+ const { status, json } = await djClient.addTag(
28
+ values.name,
29
+ values.display_name,
30
+ values.tag_type,
31
+ values.description,
32
+ );
33
+ if (status === 200 || status === 201) {
34
+ setStatus({
35
+ success: (
36
+ <>
37
+ Successfully added tag{' '}
38
+ <a href={`/tags/${json.name}`}>{json.display_name}</a>.
39
+ </>
40
+ ),
41
+ });
42
+ } else {
43
+ setStatus({
44
+ failure: `${json.message}`,
45
+ });
46
+ }
47
+ setSubmitting(false);
48
+ window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
49
+ };
50
+
51
+ return (
52
+ <div className="mid">
53
+ <NamespaceHeader namespace="" />
54
+ <div className="card">
55
+ <div className="card-header">
56
+ <h2>
57
+ Add{' '}
58
+ <span className={`node_type__source node_type_creation_heading`}>
59
+ Tag
60
+ </span>
61
+ </h2>
62
+ <center>
63
+ <Formik
64
+ initialValues={initialValues}
65
+ validate={validator}
66
+ onSubmit={handleSubmit}
67
+ >
68
+ {function Render({ isSubmitting, status }) {
69
+ return (
70
+ <Form>
71
+ {displayMessageAfterSubmit(status)}
72
+ {
73
+ <>
74
+ <div className="NodeCreationInput">
75
+ <ErrorMessage name="name" component="span" />
76
+ <label htmlFor="name">Name</label>
77
+ <Field
78
+ type="text"
79
+ name="name"
80
+ id="name"
81
+ placeholder="Tag Name"
82
+ />
83
+ </div>
84
+ <br />
85
+ <div className="FullNameInput NodeCreationInput">
86
+ <ErrorMessage name="display_name" component="span" />
87
+ <label htmlFor="display_name">Display Name</label>
88
+ <Field
89
+ type="text"
90
+ name="display_name"
91
+ id="display_name"
92
+ placeholder="Display Name"
93
+ class="FullNameField"
94
+ />
95
+ </div>
96
+ <br />
97
+ <div className="NodeCreationInput">
98
+ <ErrorMessage name="tag_type" component="span" />
99
+ <label htmlFor="tag_type">Tag Type</label>
100
+ <Field
101
+ type="text"
102
+ name="tag_type"
103
+ id="tag_type"
104
+ placeholder="Tag Type"
105
+ />
106
+ </div>
107
+ <div className="DescriptionInput NodeCreationInput">
108
+ <ErrorMessage name="description" component="span" />
109
+ <label htmlFor="description">Description</label>
110
+ <Field
111
+ type="textarea"
112
+ as="textarea"
113
+ name="description"
114
+ id="Description"
115
+ placeholder="Describe the tag"
116
+ />
117
+ </div>
118
+ <button type="submit" disabled={isSubmitting}>
119
+ Add Tag
120
+ </button>
121
+ </>
122
+ }
123
+ </Form>
124
+ );
125
+ }}
126
+ </Formik>
127
+ </center>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ );
132
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * A select component for picking dimensions
3
+ */
4
+ import { useField, useFormikContext } from 'formik';
5
+ import Select from 'react-select';
6
+ import React, { useContext, useEffect, useState } from 'react';
7
+ import DJClientContext from '../../providers/djclient';
8
+ import { labelize } from '../../../utils/form';
9
+
10
+ export const DimensionsSelect = ({ cube }) => {
11
+ const djClient = useContext(DJClientContext).DataJunctionAPI;
12
+ const { values, setFieldValue } = useFormikContext();
13
+
14
+ // eslint-disable-next-line no-unused-vars
15
+ const [field, _, helpers] = useField('dimensions');
16
+ const { setValue } = helpers;
17
+
18
+ // All common dimensions for the selected metrics, grouped by the dimension node and path
19
+ const [allDimensionsOptions, setAllDimensionsOptions] = useState([]);
20
+
21
+ // The selected dimensions, also grouped by dimension node and path
22
+ const [selectedDimensionsByGroup, setSelectedDimensionsByGroup] = useState(
23
+ {},
24
+ );
25
+
26
+ // The existing cube node's dimensions, if editing a cube
27
+ const [defaultDimensions, setDefaultDimensions] = useState([]);
28
+
29
+ useEffect(() => {
30
+ const fetchData = async () => {
31
+ let cubeDimensions = undefined;
32
+ if (cube) {
33
+ cubeDimensions = cube?.current.cubeDimensions.map(cubeDim => {
34
+ return {
35
+ value: cubeDim.name,
36
+ label:
37
+ labelize(cubeDim.attribute) +
38
+ (cubeDim.properties?.includes('primary_key') ? ' (PK)' : ''),
39
+ };
40
+ });
41
+ setDefaultDimensions(cubeDimensions);
42
+ setValue(cubeDimensions.map(m => m.value));
43
+ }
44
+
45
+ if (values.metrics && values.metrics.length > 0) {
46
+ // Populate the common dimensions list based on the selected metrics
47
+ const commonDimensions = await djClient.commonDimensions(
48
+ values.metrics,
49
+ );
50
+ const grouped = Object.entries(
51
+ commonDimensions.reduce((group, dimension) => {
52
+ group[dimension.node_name + dimension.path] =
53
+ group[dimension.node_name + dimension.path] ?? [];
54
+ group[dimension.node_name + dimension.path].push(dimension);
55
+ return group;
56
+ }, {}),
57
+ );
58
+ setAllDimensionsOptions(grouped);
59
+
60
+ // Set the selected cube dimensions if an existing cube is being edited
61
+ if (cube) {
62
+ const currentSelectedDimensionsByGroup = {};
63
+ grouped.forEach(grouping => {
64
+ const dimensionsInGroup = grouping[1];
65
+ currentSelectedDimensionsByGroup[dimensionsInGroup[0].node_name] =
66
+ getValue(
67
+ cubeDimensions.filter(
68
+ dim =>
69
+ dimensionsInGroup.filter(x => {
70
+ return dim.value === x.name;
71
+ }).length > 0,
72
+ ),
73
+ );
74
+ setSelectedDimensionsByGroup(currentSelectedDimensionsByGroup);
75
+ setValue(Object.values(currentSelectedDimensionsByGroup).flat(2));
76
+ });
77
+ }
78
+ } else {
79
+ setAllDimensionsOptions([]);
80
+ }
81
+ };
82
+ fetchData().catch(console.error);
83
+ }, [djClient, setFieldValue, setValue, values.metrics, cube]);
84
+
85
+ // Retrieves the selected values as a list (since it is a multi-select)
86
+ const getValue = options => {
87
+ if (options) {
88
+ return options.map(option => option.value);
89
+ } else {
90
+ return [];
91
+ }
92
+ };
93
+
94
+ // Builds the block of dimensions selectors, grouped by node name + path
95
+ return allDimensionsOptions.map(grouping => {
96
+ const dimensionsInGroup = grouping[1];
97
+ const groupHeader = (
98
+ <h5
99
+ style={{
100
+ fontWeight: 'normal',
101
+ marginBottom: '5px',
102
+ marginTop: '15px',
103
+ }}
104
+ >
105
+ <a href={`/nodes/${dimensionsInGroup[0].node_name}`}>
106
+ <b>{dimensionsInGroup[0].node_display_name}</b>
107
+ </a>{' '}
108
+ via{' '}
109
+ <span className="HighlightPath">
110
+ {dimensionsInGroup[0].path.join(' → ')}
111
+ </span>
112
+ </h5>
113
+ );
114
+ const dimensionGroupOptions = dimensionsInGroup.map(dim => {
115
+ return {
116
+ value: dim.name,
117
+ label:
118
+ labelize(dim.name.split('.').slice(-1)[0]) +
119
+ (dim.properties?.includes('primary_key') ? ' (PK)' : ''),
120
+ };
121
+ });
122
+ //
123
+ const cubeDimensions = defaultDimensions.filter(
124
+ dim =>
125
+ dimensionGroupOptions.filter(x => {
126
+ return dim.value === x.value;
127
+ }).length > 0,
128
+ );
129
+ return (
130
+ <>
131
+ {groupHeader}
132
+ <span data-testid={'dimensions-' + dimensionsInGroup[0].node_name}>
133
+ <Select
134
+ className=""
135
+ name={'dimensions-' + dimensionsInGroup[0].node_name}
136
+ defaultValue={cubeDimensions}
137
+ options={dimensionGroupOptions}
138
+ isMulti
139
+ isClearable
140
+ closeMenuOnSelect={false}
141
+ onChange={selected => {
142
+ selectedDimensionsByGroup[dimensionsInGroup[0].node_name] =
143
+ getValue(selected);
144
+ setSelectedDimensionsByGroup(selectedDimensionsByGroup);
145
+ setValue(Object.values(selectedDimensionsByGroup).flat(2));
146
+ }}
147
+ />
148
+ </span>
149
+ </>
150
+ );
151
+ });
152
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Asynchronously loads the component for the Node page
3
+ */
4
+
5
+ import * as React from 'react';
6
+ import { lazyLoad } from '../../../utils/loadable';
7
+
8
+ export const CubeBuilderPage = props => {
9
+ return lazyLoad(
10
+ () => import('./index'),
11
+ module => module.CubeBuilderPage,
12
+ {
13
+ fallback: <div></div>,
14
+ },
15
+ )(props);
16
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * A select component for picking metrics.
3
+ */
4
+ import { useField, useFormikContext } from 'formik';
5
+ import Select from 'react-select';
6
+ import React, { useContext, useEffect, useState } from 'react';
7
+ import DJClientContext from '../../providers/djclient';
8
+
9
+ export const MetricsSelect = ({ cube }) => {
10
+ const djClient = useContext(DJClientContext).DataJunctionAPI;
11
+ const { values } = useFormikContext();
12
+
13
+ // eslint-disable-next-line no-unused-vars
14
+ const [field, _, helpers] = useField('metrics');
15
+ const { setValue } = helpers;
16
+
17
+ // All metrics options
18
+ const [metrics, setMetrics] = useState([]);
19
+
20
+ // The existing cube's metrics, if editing a cube
21
+ const [defaultMetrics, setDefaultMetrics] = useState([]);
22
+
23
+ // Get metrics
24
+ useEffect(() => {
25
+ const fetchData = async () => {
26
+ if (cube) {
27
+ const cubeMetrics = cube?.current.cubeMetrics.map(metric => {
28
+ return {
29
+ value: metric.name,
30
+ label: metric.name,
31
+ };
32
+ });
33
+ setDefaultMetrics(cubeMetrics);
34
+ await setValue(cubeMetrics.map(m => m.value));
35
+ }
36
+
37
+ const metrics = await djClient.metrics();
38
+ setMetrics(metrics.map(m => ({ value: m, label: m })));
39
+ };
40
+ fetchData().catch(console.error);
41
+ }, [djClient, djClient.metrics, cube]);
42
+
43
+ const getValue = options => {
44
+ if (options) {
45
+ return options.map(option => option.value);
46
+ } else {
47
+ return [];
48
+ }
49
+ };
50
+
51
+ const render = () => {
52
+ if (
53
+ metrics.length > 0 ||
54
+ (cube !== undefined && defaultMetrics.length > 0 && metrics.length > 0)
55
+ ) {
56
+ return (
57
+ <Select
58
+ defaultValue={defaultMetrics}
59
+ options={metrics}
60
+ name="metrics"
61
+ placeholder={`${metrics.length} Available Metrics`}
62
+ onBlur={field.onBlur}
63
+ onChange={selected => {
64
+ setValue(getValue(selected));
65
+ }}
66
+ noOptionsMessage={() => 'No metrics found.'}
67
+ isMulti
68
+ isClearable
69
+ closeMenuOnSelect={false}
70
+ />
71
+ );
72
+ }
73
+ };
74
+ return render();
75
+ };