datajunction-ui 0.0.1-rc.17 → 0.0.1-rc.19

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 (40) hide show
  1. package/.env +1 -1
  2. package/dj-logo.svg +10 -0
  3. package/package.json +28 -6
  4. package/src/app/__tests__/__snapshots__/index.test.tsx.snap +5 -84
  5. package/src/app/components/djgraph/DJNode.jsx +1 -1
  6. package/src/app/components/djgraph/LayoutFlow.jsx +1 -1
  7. package/src/app/constants.js +2 -0
  8. package/src/app/icons/AlertIcon.jsx +32 -0
  9. package/src/app/icons/DJLogo.jsx +36 -0
  10. package/src/app/icons/DeleteIcon.jsx +21 -0
  11. package/src/app/icons/EditIcon.jsx +18 -0
  12. package/src/app/index.tsx +70 -36
  13. package/src/app/pages/AddEditNodePage/FormikSelect.jsx +33 -0
  14. package/src/app/pages/AddEditNodePage/FullNameField.jsx +36 -0
  15. package/src/app/pages/AddEditNodePage/Loadable.jsx +16 -0
  16. package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +89 -0
  17. package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +44 -0
  18. package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +29 -0
  19. package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
  20. package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +84 -0
  21. package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +353 -0
  22. package/src/app/pages/AddEditNodePage/index.jsx +349 -0
  23. package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
  24. package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
  25. package/src/app/pages/LoginPage/index.jsx +90 -0
  26. package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +50 -2
  27. package/src/app/pages/NamespacePage/index.jsx +38 -9
  28. package/src/app/pages/NodePage/NodeGraphTab.jsx +1 -2
  29. package/src/app/pages/NodePage/NodeHistory.jsx +0 -1
  30. package/src/app/pages/NodePage/index.jsx +43 -26
  31. package/src/app/pages/Root/index.tsx +20 -3
  32. package/src/app/pages/SQLBuilderPage/index.jsx +54 -8
  33. package/src/app/services/DJService.js +180 -32
  34. package/src/setupTests.ts +1 -1
  35. package/src/styles/index.css +82 -5
  36. package/src/styles/login.css +67 -0
  37. package/src/styles/node-creation.scss +190 -0
  38. package/src/styles/styles.scss +44 -0
  39. package/src/styles/styles.scss.d.ts +9 -0
  40. package/webpack.config.js +11 -1
@@ -13,6 +13,8 @@ import NodeMaterializationTab from './NodeMaterializationTab';
13
13
  import ClientCodePopover from './ClientCodePopover';
14
14
  import NodesWithDimension from './NodesWithDimension';
15
15
  import NodeColumnLineage from './NodeLineageTab';
16
+ import EditIcon from '../../icons/EditIcon';
17
+ import AlertIcon from '../../icons/AlertIcon';
16
18
 
17
19
  export function NodePage() {
18
20
  const djClient = useContext(DJClientContext).DataJunctionAPI;
@@ -109,7 +111,8 @@ export function NodePage() {
109
111
  let tabToDisplay = null;
110
112
  switch (state.selectedTab) {
111
113
  case 0:
112
- tabToDisplay = node ? <NodeInfoTab node={node} /> : '';
114
+ tabToDisplay =
115
+ node && node.message === undefined ? <NodeInfoTab node={node} /> : '';
113
116
  break;
114
117
  case 1:
115
118
  tabToDisplay = <NodeColumnTab node={node} djClient={djClient} />;
@@ -136,41 +139,55 @@ export function NodePage() {
136
139
  default:
137
140
  tabToDisplay = <NodeInfoTab node={node} />;
138
141
  }
139
-
140
142
  // @ts-ignore
141
143
  return (
142
144
  <div className="node__header">
143
145
  <NamespaceHeader namespace={name.split('.').slice(0, -1).join('.')} />
144
146
  <div className="card">
145
- <div className="card-header">
146
- <h3
147
- className="card-title align-items-start flex-column"
148
- style={{ display: 'inline-block' }}
149
- >
150
- <span className="card-label fw-bold text-gray-800">
151
- {node?.display_name}{' '}
152
- <span className={'node_type__' + node?.type + ' badge node_type'}>
153
- {node?.type}
147
+ {node !== undefined && node.message === undefined ? (
148
+ <div className="card-header">
149
+ <h3
150
+ className="card-title align-items-start flex-column"
151
+ style={{ display: 'inline-block' }}
152
+ >
153
+ <span className="card-label fw-bold text-gray-800">
154
+ {node?.display_name}{' '}
155
+ <span
156
+ className={'node_type__' + node?.type + ' badge node_type'}
157
+ >
158
+ {node?.type}
159
+ </span>
154
160
  </span>
155
- </span>
156
- </h3>
157
- <ClientCodePopover code={node?.createNodeClientCode} />
158
- <div>
159
- <a href={'/nodes/' + node?.name} className="link-table">
160
- {node?.name}
161
- </a>
162
- <span
163
- className="rounded-pill badge bg-secondary-soft"
161
+ </h3>
162
+ <a
163
+ href={`/nodes/${node?.name}/edit`}
164
164
  style={{ marginLeft: '0.5rem' }}
165
165
  >
166
- {node?.version}
167
- </span>
166
+ <EditIcon />
167
+ </a>
168
+ <ClientCodePopover code={node?.createNodeClientCode} />
169
+ <div>
170
+ <a href={'/nodes/' + node?.name} className="link-table">
171
+ {node?.name}
172
+ </a>
173
+ <span
174
+ className="rounded-pill badge bg-secondary-soft"
175
+ style={{ marginLeft: '0.5rem' }}
176
+ >
177
+ {node?.version}
178
+ </span>
179
+ </div>
180
+ <div className="align-items-center row">
181
+ {tabsList(node).map(buildTabs)}
182
+ </div>
183
+ {tabToDisplay}
168
184
  </div>
169
- <div className="align-items-center row">
170
- {tabsList(node).map(buildTabs)}
185
+ ) : (
186
+ <div className="message alert" style={{ margin: '20px' }}>
187
+ <AlertIcon />
188
+ Node `{name}` does not exist!
171
189
  </div>
172
- {tabToDisplay}
173
- </div>
190
+ )}
174
191
  </div>
175
192
  </div>
176
193
  );
@@ -1,8 +1,16 @@
1
+ import { useContext } from 'react';
1
2
  import { Outlet } from 'react-router-dom';
2
- import logo from './assets/dj-logo.png';
3
+ import DJLogo from '../../icons/DJLogo';
3
4
  import { Helmet } from 'react-helmet-async';
5
+ import DJClientContext from '../../providers/djclient';
4
6
 
5
7
  export function Root() {
8
+ const djClient = useContext(DJClientContext).DataJunctionAPI;
9
+
10
+ const handleLogout = async () => {
11
+ await djClient.logout();
12
+ window.location.reload();
13
+ };
6
14
  return (
7
15
  <>
8
16
  <Helmet>
@@ -16,8 +24,8 @@ export function Root() {
16
24
  <div className="header">
17
25
  <div className="logo">
18
26
  <h2>
19
- <img src={logo} alt="DJ Logo" width="15%" />
20
- DataJunction
27
+ <DJLogo />
28
+ Data<b>Junction</b>
21
29
  </h2>
22
30
  </div>
23
31
  <div className="menu">
@@ -46,6 +54,15 @@ export function Root() {
46
54
  </div>
47
55
  </div>
48
56
  </div>
57
+ {process.env.REACT_DISABLE_AUTH === 'true' ? (
58
+ ''
59
+ ) : (
60
+ <span className="menu-link">
61
+ <span className="menu-title">
62
+ <button onClick={handleLogout}>Logout</button>
63
+ </span>
64
+ </span>
65
+ )}
49
66
  </div>
50
67
  <Outlet />
51
68
  </>
@@ -6,10 +6,14 @@ import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
6
6
  import { foundation } from 'react-syntax-highlighter/src/styles/hljs';
7
7
  import Select from 'react-select';
8
8
  import QueryInfo from '../../components/QueryInfo';
9
+ import 'react-querybuilder/dist/query-builder.scss';
10
+ import QueryBuilder, { formatQuery } from 'react-querybuilder';
11
+ import 'styles/styles.scss';
9
12
 
10
13
  export function SQLBuilderPage() {
11
14
  const DEFAULT_NUM_ROWS = 100;
12
15
  const djClient = useContext(DJClientContext).DataJunctionAPI;
16
+ const validator = ruleType => !!ruleType.value;
13
17
  const [stagedMetrics, setStagedMetrics] = useState([]);
14
18
  const [metrics, setMetrics] = useState([]);
15
19
  const [commonDimensionsList, setCommonDimensionsList] = useState([]);
@@ -17,6 +21,8 @@ export function SQLBuilderPage() {
17
21
  const [stagedDimensions, setStagedDimensions] = useState([]);
18
22
  const [selectedMetrics, setSelectedMetrics] = useState([]);
19
23
  const [query, setQuery] = useState('');
24
+ const [fields, setFields] = useState([]);
25
+ const [filters, setFilters] = useState({ combinator: 'and', rules: [] });
20
26
  const [queryInfo, setQueryInfo] = useState({});
21
27
  const [data, setData] = useState(null);
22
28
  const [loadingData, setLoadingData] = useState(false);
@@ -48,7 +54,11 @@ export function SQLBuilderPage() {
48
54
  setQueryInfo({});
49
55
  const fetchData = async () => {
50
56
  if (process.env.REACT_USE_SSE) {
51
- const sse = await djClient.stream(selectedMetrics, selectedDimensions);
57
+ const sse = await djClient.stream(
58
+ selectedMetrics,
59
+ selectedDimensions,
60
+ formatQuery(filters, { format: 'sql', parseNumbers: true }),
61
+ );
52
62
  sse.onmessage = e => {
53
63
  const messageData = JSON.parse(JSON.parse(e.data));
54
64
  setQueryInfo(messageData);
@@ -99,6 +109,24 @@ export function SQLBuilderPage() {
99
109
  fetchData().catch(console.error);
100
110
  }, [djClient, djClient.metrics]);
101
111
 
112
+ const attributeToFormInput = dimension => {
113
+ const attribute = {
114
+ name: dimension.name,
115
+ label: `${dimension.name} (via ${dimension.path.join(' ▶ ')})`,
116
+ placeholder: `from ${dimension.path}`,
117
+ defaultOperator: '=',
118
+ validator,
119
+ };
120
+ if (dimension.type === 'bool') {
121
+ attribute.valueEditorType = 'checkbox';
122
+ }
123
+ if (dimension.type === 'timestamp') {
124
+ attribute.inputType = 'datetime-local';
125
+ attribute.defaultOperator = 'between';
126
+ }
127
+ return [dimension.name, attribute];
128
+ };
129
+
102
130
  // Get common dimensions
103
131
  useEffect(() => {
104
132
  const fetchData = async () => {
@@ -113,8 +141,15 @@ export function SQLBuilderPage() {
113
141
  path: d.path.join(' ▶ '),
114
142
  })),
115
143
  );
144
+ const uniqueFields = Object.fromEntries(
145
+ new Map(
146
+ commonDimensions.map(dimension => attributeToFormInput(dimension)),
147
+ ),
148
+ );
149
+ setFields(Object.keys(uniqueFields).map(f => uniqueFields[f]));
116
150
  } else {
117
151
  setCommonDimensionsList([]);
152
+ setFields([]);
118
153
  }
119
154
  };
120
155
  fetchData().catch(console.error);
@@ -123,15 +158,22 @@ export function SQLBuilderPage() {
123
158
  // Get SQL
124
159
  useEffect(() => {
125
160
  const fetchData = async () => {
126
- if (selectedMetrics.length && selectedDimensions.length) {
127
- const query = await djClient.sqls(selectedMetrics, selectedDimensions);
128
- setQuery(query.sql);
161
+ if (
162
+ selectedMetrics.length > 0 &&
163
+ (selectedDimensions.length > 0 || filters.rules.length > 0)
164
+ ) {
165
+ const result = await djClient.sqls(
166
+ selectedMetrics,
167
+ selectedDimensions,
168
+ formatQuery(filters, { format: 'sql', parseNumbers: true }),
169
+ );
170
+ setQuery(result.sql);
129
171
  } else {
130
172
  resetView();
131
173
  }
132
174
  };
133
175
  fetchData().catch(console.error);
134
- }, [selectedMetrics, selectedDimensions, djClient]);
176
+ }, [djClient, filters, selectedDimensions, selectedMetrics]);
135
177
 
136
178
  // Set number of rows to display
137
179
  useEffect(() => {
@@ -166,9 +208,7 @@ export function SQLBuilderPage() {
166
208
  name="metrics"
167
209
  options={metrics}
168
210
  isDisabled={
169
- selectedMetrics.length && selectedDimensions.length
170
- ? true
171
- : false
211
+ !!(selectedMetrics.length && selectedDimensions.length)
172
212
  }
173
213
  noOptionsMessage={() => 'No metrics found.'}
174
214
  placeholder={`${metrics.length} Available Metrics`}
@@ -206,6 +246,12 @@ export function SQLBuilderPage() {
206
246
  setSelectedDimensions(stagedDimensions);
207
247
  }}
208
248
  />
249
+ <h4>Filter By</h4>
250
+ <QueryBuilder
251
+ fields={fields}
252
+ query={filters}
253
+ onQueryChange={q => setFilters(q)}
254
+ />
209
255
  </div>
210
256
  <div className="card-header">
211
257
  {!viewData && !query ? (
@@ -5,8 +5,29 @@ const DJ_URL = process.env.REACT_APP_DJ_URL
5
5
  : 'http://localhost:8000';
6
6
 
7
7
  export const DataJunctionAPI = {
8
+ whoami: async function () {
9
+ const data = await (
10
+ await fetch(`${DJ_URL}/whoami/`, { credentials: 'include' })
11
+ ).json();
12
+ return data;
13
+ },
14
+
15
+ logout: async function () {
16
+ await await fetch(`${DJ_URL}/basic/logout/`, {
17
+ credentials: 'include',
18
+ method: 'POST',
19
+ });
20
+ },
21
+
8
22
  node: async function (name) {
9
- const data = await (await fetch(DJ_URL + '/nodes/' + name + '/')).json();
23
+ const data = await (
24
+ await fetch(`${DJ_URL}/nodes/${name}/`, {
25
+ credentials: 'include',
26
+ })
27
+ ).json();
28
+ if (data.message !== undefined) {
29
+ return data;
30
+ }
10
31
  data.primary_key = data.columns
11
32
  .filter(col =>
12
33
  col.attributes.some(attr => attr.attribute_type.name === 'primary_key'),
@@ -15,60 +36,150 @@ export const DataJunctionAPI = {
15
36
  return data;
16
37
  },
17
38
 
39
+ nodes: async function (prefix) {
40
+ return await (
41
+ await fetch(`${DJ_URL}/nodes/?prefix=${prefix}`, {
42
+ credentials: 'include',
43
+ })
44
+ ).json();
45
+ },
46
+
47
+ createNode: async function (
48
+ nodeType,
49
+ name,
50
+ display_name,
51
+ description,
52
+ query,
53
+ mode,
54
+ namespace,
55
+ primary_key,
56
+ ) {
57
+ const response = await fetch(`${DJ_URL}/nodes/${nodeType}`, {
58
+ method: 'POST',
59
+ headers: {
60
+ 'Content-Type': 'application/json',
61
+ },
62
+ body: JSON.stringify({
63
+ name: name,
64
+ display_name: display_name,
65
+ description: description,
66
+ query: query,
67
+ mode: mode,
68
+ namespace: namespace,
69
+ primary_key: primary_key,
70
+ }),
71
+ credentials: 'include',
72
+ });
73
+ return { status: response.status, json: await response.json() };
74
+ },
75
+
76
+ patchNode: async function (
77
+ name,
78
+ display_name,
79
+ description,
80
+ query,
81
+ mode,
82
+ primary_key,
83
+ ) {
84
+ try {
85
+ const response = await fetch(`${DJ_URL}/nodes/${name}`, {
86
+ method: 'PATCH',
87
+ headers: {
88
+ 'Content-Type': 'application/json',
89
+ },
90
+ body: JSON.stringify({
91
+ display_name: display_name,
92
+ description: description,
93
+ query: query,
94
+ mode: mode,
95
+ primary_key: primary_key,
96
+ }),
97
+ credentials: 'include',
98
+ });
99
+ return { status: response.status, json: await response.json() };
100
+ } catch (error) {
101
+ return { status: 500, json: { message: 'Update failed' } };
102
+ }
103
+ },
104
+
18
105
  upstreams: async function (name) {
19
106
  const data = await (
20
- await fetch(DJ_URL + '/nodes/' + name + '/upstream/')
107
+ await fetch(`${DJ_URL}/nodes/${name}/upstream/`, {
108
+ credentials: 'include',
109
+ })
21
110
  ).json();
22
111
  return data;
23
112
  },
24
113
 
25
114
  downstreams: async function (name) {
26
115
  const data = await (
27
- await fetch(DJ_URL + '/nodes/' + name + '/downstream/')
116
+ await fetch(`${DJ_URL}/nodes/` + name + '/downstream/', {
117
+ credentials: 'include',
118
+ })
28
119
  ).json();
29
120
  return data;
30
121
  },
31
122
 
32
123
  node_dag: async function (name) {
33
124
  const data = await (
34
- await fetch(DJ_URL + '/nodes/' + name + '/dag/')
125
+ await fetch(`${DJ_URL}/nodes/` + name + '/dag/', {
126
+ credentials: 'include',
127
+ })
35
128
  ).json();
36
129
  return data;
37
130
  },
38
131
 
39
132
  node_lineage: async function (name) {
40
133
  const data = await (
41
- await fetch(DJ_URL + '/nodes/' + name + '/lineage/')
134
+ await fetch(`${DJ_URL}/nodes/` + name + '/lineage/', {
135
+ credentials: 'include',
136
+ })
42
137
  ).json();
43
138
  return data;
44
139
  },
45
140
 
46
141
  metric: async function (name) {
47
- const data = await (await fetch(DJ_URL + '/metrics/' + name + '/')).json();
142
+ const data = await (
143
+ await fetch(`${DJ_URL}/metrics/` + name + '/', {
144
+ credentials: 'include',
145
+ })
146
+ ).json();
48
147
  return data;
49
148
  },
50
149
 
51
150
  clientCode: async function (name) {
52
151
  const data = await (
53
- await fetch(DJ_URL + '/datajunction-clients/python/new_node/' + name)
152
+ await fetch(`${DJ_URL}/datajunction-clients/python/new_node/` + name, {
153
+ credentials: 'include',
154
+ })
54
155
  ).json();
55
156
  return data;
56
157
  },
57
158
 
58
159
  cube: async function (name) {
59
- const data = await (await fetch(DJ_URL + '/cubes/' + name + '/')).json();
160
+ const data = await (
161
+ await fetch(`${DJ_URL}/cubes/` + name + '/', {
162
+ credentials: 'include',
163
+ })
164
+ ).json();
60
165
  return data;
61
166
  },
62
167
 
63
168
  metrics: async function (name) {
64
- const data = await (await fetch(DJ_URL + '/metrics/')).json();
169
+ const data = await (
170
+ await fetch(`${DJ_URL}/metrics/`, {
171
+ credentials: 'include',
172
+ })
173
+ ).json();
65
174
  return data;
66
175
  },
67
176
 
68
177
  commonDimensions: async function (metrics) {
69
178
  const metricsQuery = '?' + metrics.map(m => `metric=${m}`).join('&');
70
179
  const data = await (
71
- await fetch(DJ_URL + '/metrics/common/dimensions/' + metricsQuery)
180
+ await fetch(`${DJ_URL}/metrics/common/dimensions/` + metricsQuery, {
181
+ credentials: 'include',
182
+ })
72
183
  ).json();
73
184
  return data;
74
185
  },
@@ -76,10 +187,12 @@ export const DataJunctionAPI = {
76
187
  history: async function (type, name, offset, limit) {
77
188
  const data = await (
78
189
  await fetch(
79
- DJ_URL +
80
- '/history?node=' +
190
+ `${DJ_URL}/history?node=` +
81
191
  name +
82
192
  `&offset=${offset ? offset : 0}&limit=${limit ? limit : 100}`,
193
+ {
194
+ credentials: 'include',
195
+ },
83
196
  )
84
197
  ).json();
85
198
  return data;
@@ -87,27 +200,38 @@ export const DataJunctionAPI = {
87
200
 
88
201
  revisions: async function (name) {
89
202
  const data = await (
90
- await fetch(DJ_URL + '/nodes/' + name + '/revisions/')
203
+ await fetch(`${DJ_URL}/nodes/` + name + '/revisions/', {
204
+ credentials: 'include',
205
+ })
91
206
  ).json();
92
207
  return data;
93
208
  },
94
209
 
95
210
  namespace: async function (nmspce) {
96
211
  const data = await (
97
- await fetch(DJ_URL + '/namespaces/' + nmspce + '/')
212
+ await fetch(`${DJ_URL}/namespaces/` + nmspce + '/', {
213
+ credentials: 'include',
214
+ })
98
215
  ).json();
99
216
  return data;
100
217
  },
101
218
 
102
219
  namespaces: async function () {
103
- const data = await (await fetch(DJ_URL + '/namespaces/')).json();
220
+ const data = await (
221
+ await fetch(`${DJ_URL}/namespaces/`, {
222
+ credentials: 'include',
223
+ })
224
+ ).json();
104
225
  return data;
105
226
  },
106
227
 
107
228
  sql: async function (metric_name, selection) {
108
229
  const data = await (
109
230
  await fetch(
110
- DJ_URL + '/sql/' + metric_name + '?' + new URLSearchParams(selection),
231
+ `${DJ_URL}/sql/` + metric_name + '?' + new URLSearchParams(selection),
232
+ {
233
+ credentials: 'include',
234
+ },
111
235
  )
112
236
  ).json();
113
237
  return data;
@@ -115,22 +239,28 @@ export const DataJunctionAPI = {
115
239
 
116
240
  nodesWithDimension: async function (name) {
117
241
  const data = await (
118
- await fetch(DJ_URL + '/dimensions/' + name + '/nodes/')
242
+ await fetch(`${DJ_URL}/dimensions/` + name + '/nodes/', {
243
+ credentials: 'include',
244
+ })
119
245
  ).json();
120
246
  return data;
121
247
  },
122
248
 
123
249
  materializations: async function (node) {
124
250
  const data = await (
125
- await fetch(DJ_URL + `/nodes/${node}/materializations/`)
251
+ await fetch(`${DJ_URL}/nodes/${node}/materializations/`, {
252
+ credentials: 'include',
253
+ })
126
254
  ).json();
127
255
 
128
256
  return await Promise.all(
129
257
  data.map(async materialization => {
130
258
  materialization.clientCode = await (
131
259
  await fetch(
132
- DJ_URL +
133
- `/datajunction-clients/python/add_materialization/${node}/${materialization.name}`,
260
+ `${DJ_URL}/datajunction-clients/python/add_materialization/${node}/${materialization.name}`,
261
+ {
262
+ credentials: 'include',
263
+ },
134
264
  )
135
265
  ).json();
136
266
  return materialization;
@@ -144,8 +274,10 @@ export const DataJunctionAPI = {
144
274
  if (col.dimension) {
145
275
  col.clientCode = await (
146
276
  await fetch(
147
- DJ_URL +
148
- `/datajunction-clients/python/link_dimension/${node.name}/${col.name}/${col.dimension?.name}`,
277
+ `${DJ_URL}/datajunction-clients/python/link_dimension/${node.name}/${col.name}/${col.dimension?.name}`,
278
+ {
279
+ credentials: 'include',
280
+ },
149
281
  )
150
282
  ).json();
151
283
  }
@@ -154,12 +286,16 @@ export const DataJunctionAPI = {
154
286
  );
155
287
  },
156
288
 
157
- sqls: async function (metricSelection, dimensionSelection) {
289
+ sqls: async function (metricSelection, dimensionSelection, filters) {
158
290
  const params = new URLSearchParams();
159
291
  metricSelection.map(metric => params.append('metrics', metric));
160
292
  dimensionSelection.map(dimension => params.append('dimensions', dimension));
161
- const data = await (await fetch(DJ_URL + '/sql/?' + params)).json();
162
- return data;
293
+ params.append('filters', filters);
294
+ return await (
295
+ await fetch(`${DJ_URL}/sql/?${params}`, {
296
+ credentials: 'include',
297
+ })
298
+ ).json();
163
299
  },
164
300
 
165
301
  data: async function (metricSelection, dimensionSelection) {
@@ -167,32 +303,44 @@ export const DataJunctionAPI = {
167
303
  metricSelection.map(metric => params.append('metrics', metric));
168
304
  dimensionSelection.map(dimension => params.append('dimensions', dimension));
169
305
  const data = await (
170
- await fetch(DJ_URL + '/data/?' + params + '&limit=10000')
306
+ await fetch(`${DJ_URL}/data/?` + params + '&limit=10000', {
307
+ credentials: 'include',
308
+ })
171
309
  ).json();
172
310
  return data;
173
311
  },
174
312
 
175
- stream: async function (metricSelection, dimensionSelection) {
313
+ stream: async function (metricSelection, dimensionSelection, filters) {
176
314
  const params = new URLSearchParams();
177
315
  metricSelection.map(metric => params.append('metrics', metric));
178
316
  dimensionSelection.map(dimension => params.append('dimensions', dimension));
317
+ params.append('filters', filters);
179
318
  return new EventSource(
180
- DJ_URL + '/stream/?' + params + '&limit=10000&async_=true',
319
+ `${DJ_URL}/stream/?${params}&limit=10000&async_=true`,
320
+ {
321
+ withCredentials: true,
322
+ },
181
323
  );
182
324
  },
183
325
 
184
326
  lineage: async function (node) {},
185
327
 
186
328
  compiledSql: async function (node) {
187
- const data = await (await fetch(DJ_URL + `/sql/${node}/`)).json();
329
+ const data = await (
330
+ await fetch(`${DJ_URL}/sql/${node}/`, {
331
+ credentials: 'include',
332
+ })
333
+ ).json();
188
334
  return data;
189
335
  },
190
336
 
191
337
  dag: async function (namespace = 'default') {
192
338
  const edges = [];
193
- const data = await (await fetch(DJ_URL + '/nodes/')).json();
194
-
195
- // const metrics = await (await fetch(DJ_URL + '/metrics/')).json();
339
+ const data = await (
340
+ await fetch(`${DJ_URL}/nodes/`, {
341
+ credentials: 'include',
342
+ })
343
+ ).json();
196
344
 
197
345
  data.forEach(obj => {
198
346
  obj.parents.forEach(parent => {
package/src/setupTests.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // react-testing-library renders your components to document.body,
2
2
  // this adds jest-dom's custom assertions
3
- import '@testing-library/jest-dom/extend-expect';
3
+ import '@testing-library/jest-dom';
4
4
 
5
5
  import 'react-app-polyfill/ie11';
6
6
  import 'react-app-polyfill/stable';