datajunction-ui 0.0.23-rc.0 → 0.0.26

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 (25) hide show
  1. package/package.json +8 -2
  2. package/src/app/index.tsx +6 -0
  3. package/src/app/pages/NamespacePage/CompactSelect.jsx +100 -0
  4. package/src/app/pages/NamespacePage/NodeModeSelect.jsx +8 -5
  5. package/src/app/pages/NamespacePage/__tests__/CompactSelect.test.jsx +190 -0
  6. package/src/app/pages/NamespacePage/__tests__/index.test.jsx +297 -8
  7. package/src/app/pages/NamespacePage/index.jsx +489 -62
  8. package/src/app/pages/QueryPlannerPage/Loadable.jsx +6 -0
  9. package/src/app/pages/QueryPlannerPage/MetricFlowGraph.jsx +311 -0
  10. package/src/app/pages/QueryPlannerPage/PreAggDetailsPanel.jsx +470 -0
  11. package/src/app/pages/QueryPlannerPage/SelectionPanel.jsx +384 -0
  12. package/src/app/pages/QueryPlannerPage/__tests__/MetricFlowGraph.test.jsx +239 -0
  13. package/src/app/pages/QueryPlannerPage/__tests__/PreAggDetailsPanel.test.jsx +638 -0
  14. package/src/app/pages/QueryPlannerPage/__tests__/SelectionPanel.test.jsx +429 -0
  15. package/src/app/pages/QueryPlannerPage/__tests__/index.test.jsx +317 -0
  16. package/src/app/pages/QueryPlannerPage/index.jsx +209 -0
  17. package/src/app/pages/QueryPlannerPage/styles.css +1251 -0
  18. package/src/app/pages/Root/index.tsx +5 -0
  19. package/src/app/services/DJService.js +61 -2
  20. package/src/styles/index.css +2 -2
  21. package/src/app/icons/FilterIcon.jsx +0 -7
  22. package/src/app/pages/NamespacePage/FieldControl.jsx +0 -21
  23. package/src/app/pages/NamespacePage/NodeTypeSelect.jsx +0 -30
  24. package/src/app/pages/NamespacePage/TagSelect.jsx +0 -44
  25. package/src/app/pages/NamespacePage/UserSelect.jsx +0 -47
@@ -64,6 +64,11 @@ export function Root() {
64
64
  <a href="/sql">SQL</a>
65
65
  </span>
66
66
  </span>
67
+ <span className="menu-link">
68
+ <span className="menu-title">
69
+ <a href="/materialization-planner">Planner</a>
70
+ </span>
71
+ </span>
67
72
  <span className="menu-link">
68
73
  <span className="menu-title">
69
74
  <div className="dropdown">
@@ -19,9 +19,16 @@ export const DataJunctionAPI = {
19
19
  limit,
20
20
  sortConfig,
21
21
  mode,
22
+ {
23
+ ownedBy = null,
24
+ statuses = null,
25
+ missingDescription = false,
26
+ hasMaterialization = false,
27
+ orphanedDimension = false,
28
+ } = {},
22
29
  ) {
23
30
  const query = `
24
- query ListNodes($namespace: String, $nodeTypes: [NodeType!], $tags: [String!], $editedBy: String, $mode: NodeMode, $before: String, $after: String, $limit: Int, $orderBy: NodeSortField, $ascending: Boolean) {
31
+ query ListNodes($namespace: String, $nodeTypes: [NodeType!], $tags: [String!], $editedBy: String, $mode: NodeMode, $before: String, $after: String, $limit: Int, $orderBy: NodeSortField, $ascending: Boolean, $ownedBy: String, $statuses: [NodeStatus!], $missingDescription: Boolean, $hasMaterialization: Boolean, $orphanedDimension: Boolean) {
25
32
  findNodesPaginated(
26
33
  namespace: $namespace
27
34
  nodeTypes: $nodeTypes
@@ -31,8 +38,13 @@ export const DataJunctionAPI = {
31
38
  limit: $limit
32
39
  before: $before
33
40
  after: $after
34
- orderBy: $orderBy,
41
+ orderBy: $orderBy
35
42
  ascending: $ascending
43
+ ownedBy: $ownedBy
44
+ statuses: $statuses
45
+ missingDescription: $missingDescription
46
+ hasMaterialization: $hasMaterialization
47
+ orphanedDimension: $orphanedDimension
36
48
  ) {
37
49
  pageInfo {
38
50
  hasNextPage
@@ -92,6 +104,11 @@ export const DataJunctionAPI = {
92
104
  limit: limit,
93
105
  orderBy: sortOrderMapping[sortConfig.key],
94
106
  ascending: sortConfig.direction === 'ascending',
107
+ ownedBy: ownedBy,
108
+ statuses: statuses,
109
+ missingDescription: missingDescription,
110
+ hasMaterialization: hasMaterialization,
111
+ orphanedDimension: orphanedDimension,
95
112
  },
96
113
  }),
97
114
  })
@@ -897,6 +914,48 @@ export const DataJunctionAPI = {
897
914
  ).json();
898
915
  },
899
916
 
917
+ // V3 Measures SQL - returns pre-aggregations with components for materialization planning
918
+ measuresV3: async function (
919
+ metricSelection,
920
+ dimensionSelection,
921
+ filters = '',
922
+ ) {
923
+ const params = new URLSearchParams();
924
+ metricSelection.forEach(metric => params.append('metrics', metric));
925
+ dimensionSelection.forEach(dimension =>
926
+ params.append('dimensions', dimension),
927
+ );
928
+ if (filters) {
929
+ params.append('filters', filters);
930
+ }
931
+ return await (
932
+ await fetch(`${DJ_URL}/sql/measures/v3/?${params}`, {
933
+ credentials: 'include',
934
+ })
935
+ ).json();
936
+ },
937
+
938
+ // V3 Metrics SQL - returns final combined SQL query
939
+ metricsV3: async function (
940
+ metricSelection,
941
+ dimensionSelection,
942
+ filters = '',
943
+ ) {
944
+ const params = new URLSearchParams();
945
+ metricSelection.forEach(metric => params.append('metrics', metric));
946
+ dimensionSelection.forEach(dimension =>
947
+ params.append('dimensions', dimension),
948
+ );
949
+ if (filters) {
950
+ params.append('filters', filters);
951
+ }
952
+ return await (
953
+ await fetch(`${DJ_URL}/sql/metrics/v3/?${params}`, {
954
+ credentials: 'include',
955
+ })
956
+ ).json();
957
+ },
958
+
900
959
  data: async function (metricSelection, dimensionSelection) {
901
960
  const params = new URLSearchParams();
902
961
  metricSelection.map(metric => params.append('metrics', metric));
@@ -775,9 +775,8 @@ pre {
775
775
 
776
776
  .card-header {
777
777
  align-items: center;
778
- margin: 0.5rem;
779
778
  margin-left: 0;
780
- padding: 0 2.25rem 0 2.25rem;
779
+ padding: 1.5rem 2.25rem 0 2.25rem;
781
780
  }
782
781
 
783
782
  .card-header h2 {
@@ -1000,6 +999,7 @@ pre {
1000
999
  margin-top: 6px;
1001
1000
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
1002
1001
  min-width: 115px;
1002
+ z-index: 1100;
1003
1003
  }
1004
1004
 
1005
1005
  .dropdown:hover .dropdown-content {
@@ -1,7 +0,0 @@
1
- const FilterIcon = props => (
2
- <svg height="23px" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
3
- <path d="M20 36h8v-4h-8v4zm-14-24v4h36v-4h-36zm6 14h24v-4h-24v4z" />
4
- <path d="M0 0h48v48h-48z" fill="none" />
5
- </svg>
6
- );
7
- export default FilterIcon;
@@ -1,21 +0,0 @@
1
- import { components } from 'react-select';
2
-
3
- const Control = ({ children, ...props }) => {
4
- const { label, onLabelClick } = props.selectProps;
5
- const style = {
6
- cursor: 'pointer',
7
- padding: '10px 5px 10px 12px',
8
- color: 'rgb(112, 110, 115)',
9
- };
10
-
11
- return (
12
- <components.Control {...props}>
13
- <span onMouseDown={onLabelClick} style={style}>
14
- {label}
15
- </span>
16
- {children}
17
- </components.Control>
18
- );
19
- };
20
-
21
- export default Control;
@@ -1,30 +0,0 @@
1
- import Select from 'react-select';
2
- import Control from './FieldControl';
3
-
4
- export default function NodeTypeSelect({ onChange }) {
5
- return (
6
- <span
7
- className="menu-link"
8
- style={{ marginLeft: '30px', width: '300px' }}
9
- data-testid="select-node-type"
10
- >
11
- <Select
12
- name="node_type"
13
- isClearable
14
- label="Type"
15
- components={{ Control }}
16
- onChange={e => onChange(e)}
17
- styles={{
18
- control: styles => ({ ...styles, backgroundColor: 'white' }),
19
- }}
20
- options={[
21
- { value: 'source', label: 'Source' },
22
- { value: 'transform', label: 'Transform' },
23
- { value: 'dimension', label: 'Dimension' },
24
- { value: 'metric', label: 'Metric' },
25
- { value: 'cube', label: 'Cube' },
26
- ]}
27
- />
28
- </span>
29
- );
30
- }
@@ -1,44 +0,0 @@
1
- import { useContext, useEffect, useState } from 'react';
2
- import DJClientContext from '../../providers/djclient';
3
- import Control from './FieldControl';
4
-
5
- import Select from 'react-select';
6
-
7
- export default function TagSelect({ onChange }) {
8
- const djClient = useContext(DJClientContext).DataJunctionAPI;
9
-
10
- const [retrieved, setRetrieved] = useState(false);
11
- const [tags, setTags] = useState([]);
12
-
13
- useEffect(() => {
14
- const fetchData = async () => {
15
- const tags = await djClient.listTags();
16
- setTags(tags);
17
- setRetrieved(true);
18
- };
19
- fetchData().catch(console.error);
20
- }, [djClient]);
21
-
22
- return (
23
- <span
24
- className="menu-link"
25
- style={{ marginLeft: '30px', width: '350px' }}
26
- data-testid="select-tag"
27
- >
28
- <Select
29
- name="tags"
30
- isClearable
31
- isMulti
32
- label="Tags"
33
- components={{ Control }}
34
- onChange={e => onChange(e)}
35
- options={tags?.map(tag => {
36
- return {
37
- value: tag.name,
38
- label: tag.display_name,
39
- };
40
- })}
41
- />
42
- </span>
43
- );
44
- }
@@ -1,47 +0,0 @@
1
- import { useContext, useEffect, useState } from 'react';
2
- import DJClientContext from '../../providers/djclient';
3
- import Control from './FieldControl';
4
-
5
- import Select from 'react-select';
6
-
7
- export default function UserSelect({ onChange, currentUser }) {
8
- const djClient = useContext(DJClientContext).DataJunctionAPI;
9
- const [retrieved, setRetrieved] = useState(false);
10
- const [users, setUsers] = useState([]);
11
-
12
- useEffect(() => {
13
- const fetchData = async () => {
14
- const users = await djClient.users();
15
- setUsers(users);
16
- setRetrieved(true);
17
- };
18
- fetchData().catch(console.error);
19
- }, [djClient]);
20
-
21
- return (
22
- <span
23
- className="menu-link"
24
- style={{ marginLeft: '30px', width: '400px' }}
25
- data-testid="select-user"
26
- >
27
- {retrieved ? (
28
- <Select
29
- name="edited_by"
30
- isClearable
31
- label="Edited By"
32
- components={{ Control }}
33
- onChange={e => onChange(e)}
34
- defaultValue={{
35
- value: currentUser,
36
- label: currentUser,
37
- }}
38
- options={users?.map(user => {
39
- return { value: user.username, label: user.username };
40
- })}
41
- />
42
- ) : (
43
- ''
44
- )}
45
- </span>
46
- );
47
- }