datajunction-ui 0.0.1-rc.12 → 0.0.1-rc.14

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.
@@ -4,11 +4,11 @@ import { DataJunctionAPI } from '../../services/DJService';
4
4
  import DJClientContext from '../../providers/djclient';
5
5
  import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
6
6
  import { foundation } from 'react-syntax-highlighter/src/styles/hljs';
7
- import { format } from 'sql-formatter';
8
7
  import Select from 'react-select';
9
8
  import QueryInfo from '../../components/QueryInfo';
10
9
 
11
10
  export function SQLBuilderPage() {
11
+ const DEFAULT_NUM_ROWS = 100;
12
12
  const djClient = useContext(DJClientContext).DataJunctionAPI;
13
13
  const [stagedMetrics, setStagedMetrics] = useState([]);
14
14
  const [metrics, setMetrics] = useState([]);
@@ -17,12 +17,11 @@ export function SQLBuilderPage() {
17
17
  const [stagedDimensions, setStagedDimensions] = useState([]);
18
18
  const [selectedMetrics, setSelectedMetrics] = useState([]);
19
19
  const [query, setQuery] = useState('');
20
- const [submittedQueryInfo, setSubmittedQueryInfo] = useState(null);
20
+ const [queryInfo, setQueryInfo] = useState({});
21
21
  const [data, setData] = useState(null);
22
22
  const [loadingData, setLoadingData] = useState(false);
23
23
  const [viewData, setViewData] = useState(false);
24
- const [showHelp, setShowHelp] = useState(true);
25
- const [showNumRows, setShowNumRows] = useState(100);
24
+ const [showNumRows, setShowNumRows] = useState(DEFAULT_NUM_ROWS);
26
25
  const [displayedRows, setDisplayedRows] = useState(<></>);
27
26
  const numRowsOptions = [
28
27
  {
@@ -46,20 +45,39 @@ export function SQLBuilderPage() {
46
45
  // Get data for the current selection of metrics and dimensions
47
46
  const getData = () => {
48
47
  setLoadingData(true);
48
+ setQueryInfo({});
49
49
  const fetchData = async () => {
50
- setData(null);
51
- const queryInfo = await djClient.data(
52
- selectedMetrics,
53
- selectedDimensions,
54
- );
55
- setLoadingData(false);
56
- setSubmittedQueryInfo(queryInfo);
57
- queryInfo.numRows = 0;
58
- if (queryInfo.results && queryInfo.results?.length) {
59
- setData(queryInfo.results);
60
- queryInfo.numRows = queryInfo.results[0].rows.length;
61
- setViewData(true);
62
- setShowNumRows(10);
50
+ if (process.env.REACT_USE_SSE) {
51
+ const sse = await djClient.stream(selectedMetrics, selectedDimensions);
52
+ sse.onmessage = e => {
53
+ const messageData = JSON.parse(JSON.parse(e.data));
54
+ setQueryInfo(messageData);
55
+ if (messageData.results) {
56
+ setLoadingData(false);
57
+ setData(messageData.results);
58
+ messageData.numRows = messageData.results?.length
59
+ ? messageData.results[0].rows.length
60
+ : [];
61
+ setViewData(true);
62
+ setShowNumRows(DEFAULT_NUM_ROWS);
63
+ }
64
+ };
65
+ sse.onerror = () => sse.close();
66
+ } else {
67
+ const response = await djClient.data(
68
+ selectedMetrics,
69
+ selectedDimensions,
70
+ );
71
+ setQueryInfo(response);
72
+ if (response.results) {
73
+ setLoadingData(false);
74
+ setData(response.results);
75
+ response.numRows = response.results?.length
76
+ ? response.results[0].rows.length
77
+ : [];
78
+ setViewData(true);
79
+ setShowNumRows(DEFAULT_NUM_ROWS);
80
+ }
63
81
  }
64
82
  };
65
83
  fetchData().catch(console.error);
@@ -69,25 +87,7 @@ export function SQLBuilderPage() {
69
87
  setQuery('');
70
88
  setData(null);
71
89
  setViewData(false);
72
- };
73
- const handleMetricSelect = event => {
74
- const metrics = event.map(m => m.value);
75
- resetView();
76
- setStagedMetrics(metrics);
77
- };
78
-
79
- const handleMetricSelectorClose = () => {
80
- setSelectedMetrics(stagedMetrics);
81
- };
82
-
83
- const handleDimensionSelect = event => {
84
- const dimensions = event.map(d => d.value);
85
- resetView();
86
- setStagedDimensions(dimensions);
87
- };
88
-
89
- const handleDimensionSelectorClose = () => {
90
- setSelectedDimensions(stagedDimensions);
90
+ setQueryInfo({});
91
91
  };
92
92
 
93
93
  // Get metrics
@@ -125,11 +125,9 @@ export function SQLBuilderPage() {
125
125
  const fetchData = async () => {
126
126
  if (selectedMetrics.length && selectedDimensions.length) {
127
127
  const query = await djClient.sqls(selectedMetrics, selectedDimensions);
128
- setShowHelp(false);
129
128
  setQuery(query.sql);
130
129
  } else {
131
130
  resetView();
132
- setShowHelp(true);
133
131
  }
134
132
  };
135
133
  fetchData().catch(console.error);
@@ -139,7 +137,7 @@ export function SQLBuilderPage() {
139
137
  useEffect(() => {
140
138
  if (data) {
141
139
  setDisplayedRows(
142
- data[0].rows.slice(0, showNumRows).map((rowData, index) => (
140
+ data[0]?.rows.slice(0, showNumRows).map((rowData, index) => (
143
141
  <tr key={`data-row:${index}`}>
144
142
  {rowData.map(rowValue => (
145
143
  <td key={rowValue}>{rowValue}</td>
@@ -167,15 +165,28 @@ export function SQLBuilderPage() {
167
165
  <Select
168
166
  name="metrics"
169
167
  options={metrics}
168
+ isDisabled={
169
+ selectedMetrics.length && selectedDimensions.length
170
+ ? true
171
+ : false
172
+ }
170
173
  noOptionsMessage={() => 'No metrics found.'}
171
174
  placeholder={`${metrics.length} Available Metrics`}
172
175
  isMulti
173
176
  isClearable
174
177
  closeMenuOnSelect={false}
175
- onChange={handleMetricSelect}
176
- onMenuClose={handleMetricSelectorClose}
178
+ onChange={e => {
179
+ setSelectedDimensions([]);
180
+ resetView();
181
+ setStagedMetrics(e.map(m => m.value));
182
+ }}
183
+ onMenuClose={() => {
184
+ resetView();
185
+ setSelectedDimensions([]);
186
+ setSelectedMetrics(stagedMetrics);
187
+ }}
177
188
  />
178
- <h4>Shared Dimensions</h4>
189
+ <h4>Group By</h4>
179
190
  <Select
180
191
  name="dimensions"
181
192
  formatOptionLabel={formatOptionLabel}
@@ -187,12 +198,17 @@ export function SQLBuilderPage() {
187
198
  isMulti
188
199
  isClearable
189
200
  closeMenuOnSelect={false}
190
- onChange={handleDimensionSelect}
191
- onMenuClose={handleDimensionSelectorClose}
201
+ onChange={e => {
202
+ resetView();
203
+ setStagedDimensions(e.map(d => d.value));
204
+ }}
205
+ onMenuClose={() => {
206
+ setSelectedDimensions(stagedDimensions);
207
+ }}
192
208
  />
193
209
  </div>
194
210
  <div className="card-header">
195
- {showHelp ? (
211
+ {!viewData && !query ? (
196
212
  <div className="card-light-shadow">
197
213
  <h6>Using the SQL Builder</h6>
198
214
  <p>
@@ -272,18 +288,11 @@ export function SQLBuilderPage() {
272
288
  ) : (
273
289
  <></>
274
290
  )}
275
- {submittedQueryInfo ? <QueryInfo {...submittedQueryInfo} /> : <></>}
291
+ {queryInfo && queryInfo.id ? <QueryInfo {...queryInfo} /> : <></>}
276
292
  <div>
277
293
  {query && !viewData ? (
278
294
  <SyntaxHighlighter language="sql" style={foundation}>
279
- {format(query, {
280
- language: 'spark',
281
- tabWidth: 2,
282
- keywordCase: 'upper',
283
- denseOperators: true,
284
- logicalOperatorNewline: 'before',
285
- expressionWidth: 10,
286
- })}
295
+ {query}
287
296
  </SyntaxHighlighter>
288
297
  ) : (
289
298
  ''
@@ -294,7 +303,7 @@ export function SQLBuilderPage() {
294
303
  <table className="card-inner-table table">
295
304
  <thead className="fs-7 fw-bold text-gray-400 border-bottom-0">
296
305
  <tr>
297
- {data[0].columns.map(columnName => (
306
+ {data[0]?.columns.map(columnName => (
298
307
  <th key={columnName.name}>{columnName.name}</th>
299
308
  ))}
300
309
  </tr>
@@ -36,6 +36,13 @@ export const DataJunctionAPI = {
36
36
  return data;
37
37
  },
38
38
 
39
+ node_lineage: async function (name) {
40
+ const data = await (
41
+ await fetch(DJ_URL + '/nodes/' + name + '/lineage/')
42
+ ).json();
43
+ return data;
44
+ },
45
+
39
46
  metric: async function (name) {
40
47
  const data = await (await fetch(DJ_URL + '/metrics/' + name + '/')).json();
41
48
  return data;
@@ -43,7 +50,7 @@ export const DataJunctionAPI = {
43
50
 
44
51
  clientCode: async function (name) {
45
52
  const data = await (
46
- await fetch(DJ_URL + '/client/python/new_node/' + name)
53
+ await fetch(DJ_URL + '/datajunction-clients/python/new_node/' + name)
47
54
  ).json();
48
55
  return data;
49
56
  },
@@ -70,11 +77,9 @@ export const DataJunctionAPI = {
70
77
  const data = await (
71
78
  await fetch(
72
79
  DJ_URL +
73
- '/history/' +
74
- type +
75
- '/' +
80
+ '/history?node=' +
76
81
  name +
77
- `/?offset=${offset ? offset : 0}&limit=${limit ? limit : 100}`,
82
+ `&offset=${offset ? offset : 0}&limit=${limit ? limit : 100}`,
78
83
  )
79
84
  ).json();
80
85
  return data;
@@ -108,6 +113,13 @@ export const DataJunctionAPI = {
108
113
  return data;
109
114
  },
110
115
 
116
+ nodesWithDimension: async function (name) {
117
+ const data = await (
118
+ await fetch(DJ_URL + '/dimensions/' + name + '/nodes/')
119
+ ).json();
120
+ return data;
121
+ },
122
+
111
123
  materializations: async function (node) {
112
124
  const data = await (
113
125
  await fetch(DJ_URL + `/nodes/${node}/materializations/`)
@@ -118,7 +130,7 @@ export const DataJunctionAPI = {
118
130
  materialization.clientCode = await (
119
131
  await fetch(
120
132
  DJ_URL +
121
- `/client/python/add_materialization/${node}/${materialization.name}`,
133
+ `/datajunction-clients/python/add_materialization/${node}/${materialization.name}`,
122
134
  )
123
135
  ).json();
124
136
  return materialization;
@@ -129,12 +141,14 @@ export const DataJunctionAPI = {
129
141
  columns: async function (node) {
130
142
  return await Promise.all(
131
143
  node.columns.map(async col => {
132
- col.clientCode = await (
133
- await fetch(
134
- DJ_URL +
135
- `/client/python/link_dimension/${node.name}/${col.name}/${col.dimension?.name}`,
136
- )
137
- ).json();
144
+ if (col.dimension !== null) {
145
+ col.clientCode = await (
146
+ await fetch(
147
+ DJ_URL +
148
+ `/datajunction-clients/python/link_dimension/${node.name}/${col.name}/${col.dimension?.name}`,
149
+ )
150
+ ).json();
151
+ }
138
152
  return col;
139
153
  }),
140
154
  );
@@ -153,11 +167,20 @@ export const DataJunctionAPI = {
153
167
  metricSelection.map(metric => params.append('metrics', metric));
154
168
  dimensionSelection.map(dimension => params.append('dimensions', dimension));
155
169
  const data = await (
156
- await fetch(DJ_URL + '/data/?' + params + '&limit=100&async_=true')
170
+ await fetch(DJ_URL + '/data/?' + params + '&limit=10000')
157
171
  ).json();
158
172
  return data;
159
173
  },
160
174
 
175
+ stream: async function (metricSelection, dimensionSelection) {
176
+ const params = new URLSearchParams();
177
+ metricSelection.map(metric => params.append('metrics', metric));
178
+ dimensionSelection.map(dimension => params.append('dimensions', dimension));
179
+ return new EventSource(
180
+ DJ_URL + '/stream/?' + params + '&limit=10000&async_=true',
181
+ );
182
+ },
183
+
161
184
  lineage: async function (node) {},
162
185
 
163
186
  compiledSql: async function (node) {
@@ -265,15 +265,18 @@ tr {
265
265
  left: 0;
266
266
  }
267
267
 
268
- .table-responsive {
268
+ .table-responsive,
269
+ .table-vertical {
269
270
  overflow-x: auto;
270
271
  -webkit-overflow-scrolling: touch;
271
272
  display: grid;
272
-
273
273
  grid-template-columns: auto auto auto;
274
274
  grid-gap: 8px;
275
275
  padding: 8px;
276
276
  }
277
+ .table-vertical {
278
+ display: contents;
279
+ }
277
280
  .table > thead {
278
281
  vertical-align: bottom;
279
282
  }
@@ -430,12 +433,12 @@ tbody th {
430
433
  color: #00b368;
431
434
  }
432
435
 
433
- .history_type__deactvate {
434
- background-color: #a8a8a8 !important;
435
- color: #855e5e;
436
+ .history_type__delete {
437
+ background-color: #ffc8c8 !important;
438
+ color: #9b5a5a;
436
439
  }
437
440
 
438
- .history_type__activate {
441
+ .history_type__restore {
439
442
  background-color: #ccf7e5 !important;
440
443
  color: #00b368;
441
444
  }
@@ -456,8 +459,13 @@ tbody th {
456
459
  }
457
460
 
458
461
  .history_type__set_attribute {
459
- background-color: #a8a8a8 !important;
460
- color: #855e5e;
462
+ background-color: #e6f5ff !important;
463
+ color: #487c8c;
464
+ }
465
+
466
+ .history_type__status_change {
467
+ background-color: #ffe9db !important;
468
+ color: #573d3d;
461
469
  }
462
470
 
463
471
  .partition_value {
package/webpack.config.js CHANGED
@@ -99,6 +99,7 @@ module.exports = {
99
99
  plugins: [
100
100
  new HtmlWebpackPlugin({
101
101
  template: path.resolve(__dirname, 'public', 'index.html'),
102
+ favicon: path.resolve(__dirname, 'public', 'favicon.ico'),
102
103
  }),
103
104
  new webpack.DefinePlugin({
104
105
  'process.env': JSON.stringify(process.env),