@cubejs-client/react 1.7.13 → 1.7.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.
Files changed (62) hide show
  1. package/dist/CubeContext.d.ts +35 -0
  2. package/dist/CubeContext.d.ts.map +1 -0
  3. package/dist/CubeProvider.d.ts +31 -0
  4. package/dist/CubeProvider.d.ts.map +1 -0
  5. package/dist/QueryBuilder.d.ts +135 -0
  6. package/dist/QueryBuilder.d.ts.map +1 -0
  7. package/dist/QueryRenderer.d.ts +34 -0
  8. package/dist/QueryRenderer.d.ts.map +1 -0
  9. package/dist/QueryRendererWithTotals.d.ts +4 -0
  10. package/dist/QueryRendererWithTotals.d.ts.map +1 -0
  11. package/dist/cubejs-client-react.cjs.js +248 -23
  12. package/dist/cubejs-client-react.cjs.js.map +1 -1
  13. package/dist/cubejs-client-react.esm.js +253 -31
  14. package/dist/cubejs-client-react.esm.js.map +1 -1
  15. package/dist/cubejs-client-react.umd.js +248 -23
  16. package/dist/cubejs-client-react.umd.js.map +1 -1
  17. package/dist/hooks/cube-fetch.d.ts +6 -0
  18. package/dist/hooks/cube-fetch.d.ts.map +1 -0
  19. package/dist/hooks/cube-meta.d.ts +4 -0
  20. package/dist/hooks/cube-meta.d.ts.map +1 -0
  21. package/dist/hooks/cube-query.d.ts +39 -0
  22. package/dist/hooks/cube-query.d.ts.map +1 -0
  23. package/dist/hooks/cube-sql.d.ts +12 -0
  24. package/dist/hooks/cube-sql.d.ts.map +1 -0
  25. package/dist/hooks/deep-compare-memoize.d.ts +2 -0
  26. package/dist/hooks/deep-compare-memoize.d.ts.map +1 -0
  27. package/dist/hooks/dry-run.d.ts +7 -0
  28. package/dist/hooks/dry-run.d.ts.map +1 -0
  29. package/dist/hooks/lazy-dry-run.d.ts +7 -0
  30. package/dist/hooks/lazy-dry-run.d.ts.map +1 -0
  31. package/dist/index.d.ts +21 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/types.d.ts +765 -0
  34. package/dist/types.d.ts.map +1 -0
  35. package/dist/utils.d.ts +2 -0
  36. package/dist/utils.d.ts.map +1 -0
  37. package/package.json +14 -10
  38. package/src/CubeContext.ts +37 -0
  39. package/src/CubeProvider.tsx +42 -0
  40. package/src/{QueryBuilder.jsx → QueryBuilder.tsx} +238 -89
  41. package/src/{QueryRenderer.jsx → QueryRenderer.tsx} +39 -14
  42. package/src/QueryRendererWithTotals.tsx +24 -0
  43. package/src/hooks/cube-fetch.ts +98 -0
  44. package/src/hooks/cube-meta.ts +8 -0
  45. package/src/hooks/{cube-query.js → cube-query.ts} +90 -14
  46. package/src/hooks/cube-sql.ts +22 -0
  47. package/src/hooks/{deep-compare-memoize.js → deep-compare-memoize.ts} +2 -2
  48. package/src/hooks/dry-run.ts +17 -0
  49. package/src/hooks/lazy-dry-run.ts +24 -0
  50. package/src/index.ts +77 -0
  51. package/src/types.ts +837 -0
  52. package/src/{utils.js → utils.ts} +3 -3
  53. package/index.d.ts +0 -697
  54. package/src/CubeContext.js +0 -3
  55. package/src/CubeProvider.jsx +0 -14
  56. package/src/QueryRendererWithTotals.jsx +0 -20
  57. package/src/hooks/cube-fetch.js +0 -66
  58. package/src/hooks/cube-meta.js +0 -5
  59. package/src/hooks/cube-sql.js +0 -8
  60. package/src/hooks/dry-run.js +0 -8
  61. package/src/hooks/lazy-dry-run.js +0 -11
  62. package/src/index.js +0 -18
@@ -12,12 +12,60 @@ import {
12
12
  ResultSet,
13
13
  removeEmptyQueryFields
14
14
  } from '@cubejs-client/core';
15
+ import type {
16
+ CubeApi,
17
+ CubeMember,
18
+ DryRunResponse,
19
+ Meta,
20
+ NotFoundMember,
21
+ PivotConfig,
22
+ PivotQuery,
23
+ Query,
24
+ QueryOrder,
25
+ RequestError,
26
+ TCubeDimension,
27
+ TCubeMeasure,
28
+ TCubeSegment,
29
+ TDefaultHeuristicsState,
30
+ TOrderMember,
31
+ } from '@cubejs-client/core';
15
32
 
16
- import QueryRenderer from './QueryRenderer.jsx';
33
+ import QueryRenderer from './QueryRenderer';
17
34
  import CubeContext from './CubeContext';
18
35
  import { removeEmpty } from './utils';
19
-
20
- const granularities = [
36
+ import type {
37
+ AvailableCube,
38
+ AvailableMembers,
39
+ ChartType,
40
+ CubeContextProps,
41
+ FilterUpdateFields,
42
+ FilterUpdateInput,
43
+ GranularityOption,
44
+ IndexedDimension,
45
+ IndexedMeasure,
46
+ IndexedSegment,
47
+ MemberUpdater,
48
+ MemberUpdaterFactory,
49
+ MetaErrorSource,
50
+ MutexObj,
51
+ PivotConfigUpdaterArgs,
52
+ QueryBuilderInternalState,
53
+ QueryBuilderProps,
54
+ QueryBuilderRenderProps,
55
+ QueryBuilderState,
56
+ QueryBuilderStateUpdate,
57
+ QueryMemberType,
58
+ QueryRendererRenderProps,
59
+ ResolvedFilter,
60
+ ResolveMemberArgs,
61
+ ResolvedTimeDimension,
62
+ TimeDimensionComparisonUpdateFields,
63
+ TimeDimensionRangedUpdateFields,
64
+ TimeDimensionUpdateInput,
65
+ TimeDimensionWithExtraFields,
66
+ } from './types';
67
+
68
+ const granularities: GranularityOption[] = [
21
69
  { name: undefined, title: 'w/o grouping' },
22
70
  { name: 'second', title: 'Second' },
23
71
  { name: 'minute', title: 'Minute' },
@@ -29,7 +77,71 @@ const granularities = [
29
77
  { name: 'year', title: 'Year' },
30
78
  ];
31
79
 
32
- export default class QueryBuilder extends React.Component {
80
+ /**
81
+ * `<QueryBuilder />` is used to build interactive analytics query builders. It abstracts state management and API calls to Cube.js Backend. It uses render prop technique and doesn’t render anything itself, but calls the render function instead.
82
+ *
83
+ * **Example**
84
+ *
85
+ * [Open in CodeSandbox](https://codesandbox.io/s/z6r7qj8wm)
86
+ * ```js
87
+ * import React from 'react';
88
+ * import ReactDOM from 'react-dom';
89
+ * import { Layout, Divider, Empty, Select } from 'antd';
90
+ * import { QueryBuilder } from '@cubejs-client/react';
91
+ * import cube from '@cubejs-client/core';
92
+ * import 'antd/dist/antd.css';
93
+ *
94
+ * import ChartRenderer from './ChartRenderer';
95
+ *
96
+ * const cubeApi = cube('YOUR-CUBE-API-TOKEN', {
97
+ * apiUrl: 'http://localhost:4000/cubejs-api/v1',
98
+ * });
99
+ *
100
+ * const App = () => (
101
+ * <QueryBuilder
102
+ * query={{
103
+ * timeDimensions: [
104
+ * {
105
+ * dimension: 'LineItems.createdAt',
106
+ * granularity: 'month',
107
+ * },
108
+ * ],
109
+ * }}
110
+ * cubeApi={cubeApi}
111
+ * render={({ resultSet, measures, availableMeasures, updateMeasures }) => (
112
+ * <Layout.Content style={{ padding: '20px' }}>
113
+ * <Select
114
+ * mode="multiple"
115
+ * style={{ width: '100%' }}
116
+ * placeholder="Please select"
117
+ * onSelect={(measure) => updateMeasures.add(measure)}
118
+ * onDeselect={(measure) => updateMeasures.remove(measure)}
119
+ * >
120
+ * {availableMeasures.map((measure) => (
121
+ * <Select.Option key={measure.name} value={measure}>
122
+ * {measure.title}
123
+ * </Select.Option>
124
+ * ))}
125
+ * </Select>
126
+ * <Divider />
127
+ * {measures.length > 0 ? (
128
+ * <ChartRenderer resultSet={resultSet} />
129
+ * ) : (
130
+ * <Empty description="Select measure or dimension to get started" />
131
+ * )}
132
+ * </Layout.Content>
133
+ * )}
134
+ * />
135
+ * );
136
+ *
137
+ * const rootElement = document.getElementById("root");
138
+ * ReactDOM.render(<App />, rootElement);
139
+ * ```
140
+ * @stickyTypes QueryBuilderProps, QueryBuilderRenderProps, QueryBuilderState
141
+ * @noInheritDoc
142
+ * @order 2
143
+ */
144
+ export default class QueryBuilder extends React.Component<QueryBuilderProps, QueryBuilderInternalState> {
33
145
  static contextType = CubeContext;
34
146
 
35
147
  static defaultProps = {
@@ -52,7 +164,7 @@ export default class QueryBuilder extends React.Component {
52
164
 
53
165
  // This is an anti-pattern, only kept for backward compatibility
54
166
  // https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#anti-pattern-unconditionally-copying-props-to-state
55
- static getDerivedStateFromProps(props, state) {
167
+ static getDerivedStateFromProps(props: QueryBuilderProps, state: QueryBuilderInternalState) {
56
168
  if (props.query || props.vizState) {
57
169
  const nextState = {
58
170
  ...state,
@@ -74,13 +186,16 @@ export default class QueryBuilder extends React.Component {
74
186
  return null;
75
187
  }
76
188
 
77
- static resolveMember(type, { meta, query }) {
189
+ static resolveMember(
190
+ type: QueryMemberType,
191
+ { meta, query }: ResolveMemberArgs
192
+ ): unknown[] {
78
193
  if (!meta) {
79
194
  return [];
80
195
  }
81
196
 
82
197
  if (Array.isArray(query)) {
83
- return query.reduce(
198
+ return query.reduce<unknown[]>(
84
199
  (memo, currentQuery) => memo.concat(
85
200
  QueryBuilder.resolveMember(type, {
86
201
  meta,
@@ -95,7 +210,7 @@ export default class QueryBuilder extends React.Component {
95
210
  return (query.timeDimensions || []).map((m, index) => ({
96
211
  ...m,
97
212
  dimension: {
98
- ...meta.resolveMember(m.dimension, 'dimensions'),
213
+ ...(meta.resolveMember(m.dimension, 'dimensions') as TCubeDimension),
99
214
  granularities,
100
215
  },
101
216
  index,
@@ -104,15 +219,15 @@ export default class QueryBuilder extends React.Component {
104
219
 
105
220
  return (query[type] || []).map((m, index) => ({
106
221
  index,
107
- ...meta.resolveMember(m, type),
222
+ ...(meta.resolveMember(m, type) as CubeMember),
108
223
  }));
109
224
  }
110
225
 
111
- constructor(props) {
226
+ constructor(props: QueryBuilderProps) {
112
227
  super(props);
113
228
 
114
229
  this.state = {
115
- query: props.defaultQuery || props.query,
230
+ query: (props.defaultQuery || props.query) as Query,
116
231
  chartType: props.defaultChartType,
117
232
  validatedQuery: props.query, // deprecated, validatedQuery should not be set until after dry-run for safety
118
233
  missingMembers: [],
@@ -132,7 +247,7 @@ export default class QueryBuilder extends React.Component {
132
247
  await this.fetchMeta();
133
248
  }
134
249
 
135
- async componentDidUpdate(prevProps) {
250
+ async componentDidUpdate(prevProps: QueryBuilderProps) {
136
251
  const { schemaVersion, onSchemaChange } = this.props;
137
252
  const { meta } = this.state;
138
253
 
@@ -146,7 +261,7 @@ export default class QueryBuilder extends React.Component {
146
261
  const newMeta = await this.cubeApi().meta();
147
262
  if (!equals(newMeta, meta) && typeof onSchemaChange === 'function') {
148
263
  onSchemaChange({
149
- schemaVersion,
264
+ schemaVersion: schemaVersion as number,
150
265
  refresh: async () => {
151
266
  await this.fetchMeta();
152
267
  },
@@ -154,28 +269,44 @@ export default class QueryBuilder extends React.Component {
154
269
  }
155
270
  } catch (error) {
156
271
  // eslint-disable-next-line
157
- this.setState({ metaError: error });
272
+ this.setState({ metaError: error as Error });
158
273
  }
159
274
  }
160
275
  }
161
276
 
277
+ // These sit after the lifecycle methods because `react/sort-comp` sorts
278
+ // TypeScript field declarations into `everything-else`, which the configured
279
+ // order puts after `lifecycle`. Runtime is unaffected: field initializers run
280
+ // right after `super()`, so the constructor's assignments still win.
281
+ //
282
+ // `this.context` is not re-declared: React types it as `any`, and a field
283
+ // declaration would be emitted at runtime and shadow the context React
284
+ // assigns.
285
+ private mutexObj: MutexObj;
286
+
287
+ private orderMembersOrderKeys: string[];
288
+
289
+ private prevContext?: CubeContextProps;
290
+
162
291
  fetchMeta = async () => {
163
292
  if (!this.cubeApi()) {
164
293
  return;
165
294
  }
166
295
 
167
- let meta;
168
- let metaError = null;
169
- let richMetaError = null;
170
- let metaErrorStack = null;
296
+ let meta: Meta | undefined;
297
+ let metaError: MetaErrorSource | null = null;
298
+ let richMetaError: Error | null = null;
299
+ let metaErrorStack: string | null = null;
171
300
 
172
301
  try {
173
302
  this.setState({ isFetchingMeta: true });
174
303
  meta = await this.cubeApi().meta();
175
304
  } catch (error) {
176
- metaError = error.response?.plainError || error;
177
- richMetaError = error;
178
- metaErrorStack = error.response?.stack?.replace(error.message || '', '') || '';
305
+ const requestError = error as RequestError;
306
+
307
+ metaError = requestError.response?.plainError || requestError;
308
+ richMetaError = requestError;
309
+ metaErrorStack = requestError.response?.stack?.replace(requestError.message || '', '') || '';
179
310
  }
180
311
 
181
312
  this.setState(
@@ -194,26 +325,26 @@ export default class QueryBuilder extends React.Component {
194
325
  );
195
326
  };
196
327
 
197
- cubeApi() {
328
+ cubeApi(): CubeApi {
198
329
  const { cubeApi } = this.props;
199
330
  // eslint-disable-next-line react/destructuring-assignment
200
331
  return cubeApi || (this.context && this.context.cubeApi);
201
332
  }
202
333
 
203
- getMissingMembers(query, meta) {
334
+ getMissingMembers(query: Query, meta?: Meta) {
204
335
  if (!meta) {
205
336
  return [];
206
337
  }
207
338
 
208
339
  return getQueryMembers(query)
209
340
  .map((member) => {
210
- const resolvedMember = meta.resolveMember(member, ['measures', 'dimensions', 'segments']);
341
+ const resolvedMember = meta.resolveMember(member, ['measures', 'dimensions', 'segments']) as NotFoundMember;
211
342
  if (resolvedMember.error) {
212
343
  return member;
213
344
  }
214
345
  return false;
215
346
  })
216
- .filter(Boolean);
347
+ .filter(Boolean) as string[];
217
348
  }
218
349
 
219
350
  isQueryPresent() {
@@ -221,10 +352,10 @@ export default class QueryBuilder extends React.Component {
221
352
  return QueryRenderer.isQueryPresent(query);
222
353
  }
223
354
 
224
- prepareRenderProps(queryRendererProps) {
225
- const getName = (member) => member.name;
355
+ prepareRenderProps(queryRendererProps?: QueryRendererRenderProps): QueryBuilderRenderProps {
356
+ const getName = (member: unknown) => (member as CubeMember).name;
226
357
 
227
- const toTimeDimension = (member) => {
358
+ const toTimeDimension = (member: TimeDimensionUpdateInput) => {
228
359
  const rangeSelection = member.compareDateRange
229
360
  ? { compareDateRange: member.compareDateRange }
230
361
  : { dateRange: member.dateRange };
@@ -236,33 +367,33 @@ export default class QueryBuilder extends React.Component {
236
367
  });
237
368
  };
238
369
 
239
- const toFilter = (member) => ({
370
+ const toFilter = (member: FilterUpdateInput) => ({
240
371
  member: member.member?.name || member.dimension?.name,
241
372
  operator: member.operator,
242
373
  ...(['set', 'notSet'].includes(member.operator) ? {} : { values: member.values }),
243
374
  });
244
375
 
245
- const updateMethods = (memberType, toQuery = getName) => ({
376
+ const updateMethods: MemberUpdaterFactory = (memberType, toQuery = getName) => ({
246
377
  add: (member) => {
247
378
  const { query } = this.state;
248
379
  this.updateQuery({
249
- [memberType]: (query[memberType] || []).concat(toQuery(member)),
250
- });
380
+ [memberType]: ((query[memberType] || []) as unknown[]).concat(toQuery(member)),
381
+ } as Query);
251
382
  },
252
383
  remove: (member) => {
253
384
  const { query } = this.state;
254
385
 
255
386
  return this.updateQuery({
256
- [memberType]: (query[memberType] || []).filter((_, index) => index !== member.index),
257
- });
387
+ [memberType]: ((query[memberType] || []) as unknown[]).filter((_, index) => index !== member.index),
388
+ } as Query);
258
389
  },
259
390
  update: (member, updateWith) => {
260
391
  const { query } = this.state;
261
- const members = (query[memberType] || []).concat([]);
392
+ const members = ((query[memberType] || []) as unknown[]).concat([]);
262
393
  members.splice(member.index, 1, toQuery(updateWith));
263
394
  return this.updateQuery({
264
395
  [memberType]: members,
265
- });
396
+ } as Query);
266
397
  },
267
398
  });
268
399
 
@@ -287,27 +418,30 @@ export default class QueryBuilder extends React.Component {
287
418
  member: filter.member || filter.dimension,
288
419
  })));
289
420
 
290
- const filters = flatFilters.map((m, i) => ({
421
+ const filters: ResolvedFilter[] = flatFilters.map((m, i) => ({
291
422
  ...m,
292
- dimension: meta.resolveMember(m.member || m.dimension, ['dimensions', 'measures']),
293
- operators: meta.filterOperatorsForMember(m.member || m.dimension, ['dimensions', 'measures']),
423
+ dimension: meta!.resolveMember(
424
+ m.member || m.dimension!,
425
+ ['dimensions', 'measures']
426
+ ) as TCubeDimension | TCubeMeasure,
427
+ operators: meta!.filterOperatorsForMember(m.member || m.dimension!, ['dimensions', 'measures']),
294
428
  index: i,
295
429
  }));
296
430
 
297
- const measures = QueryBuilder.resolveMember('measures', this.state);
298
- const dimensions = QueryBuilder.resolveMember('dimensions', this.state);
299
- const timeDimensions = QueryBuilder.resolveMember('timeDimensions', this.state);
300
- const segments = ((meta && query.segments) || []).map((m, i) => ({
431
+ const measures = QueryBuilder.resolveMember('measures', this.state) as IndexedMeasure[];
432
+ const dimensions = QueryBuilder.resolveMember('dimensions', this.state) as IndexedDimension[];
433
+ const timeDimensions = QueryBuilder.resolveMember('timeDimensions', this.state) as ResolvedTimeDimension[];
434
+ const segments: IndexedSegment[] = ((meta && query.segments) || []).map((m, i) => ({
301
435
  index: i,
302
- ...meta.resolveMember(m, 'segments'),
436
+ ...(meta!.resolveMember(m, 'segments') as TCubeSegment),
303
437
  }));
304
438
 
305
- let availableMeasures = [];
306
- let availableDimensions = [];
307
- let availableSegments = [];
308
- let availableFilterMembers = [];
439
+ let availableMeasures: TCubeMeasure[] = [];
440
+ let availableDimensions: TCubeDimension[] = [];
441
+ let availableSegments: TCubeSegment[] = [];
442
+ let availableFilterMembers: Array<AvailableCube<TCubeMeasure> | AvailableCube<TCubeDimension>> = [];
309
443
 
310
- const availableMembers = meta?.membersGroupedByCube() || {
444
+ const availableMembers: AvailableMembers = meta?.membersGroupedByCube() || {
311
445
  measures: [],
312
446
  dimensions: [],
313
447
  segments: [],
@@ -315,15 +449,17 @@ export default class QueryBuilder extends React.Component {
315
449
  };
316
450
 
317
451
  if (meta) {
318
- availableMeasures = meta.membersForQuery(query, 'measures');
319
- availableDimensions = meta.membersForQuery(query, 'dimensions');
320
- availableSegments = meta.membersForQuery(query, 'segments');
452
+ availableMeasures = meta.membersForQuery(query, 'measures') as TCubeMeasure[];
453
+ availableDimensions = meta.membersForQuery(query, 'dimensions') as TCubeDimension[];
454
+ availableSegments = meta.membersForQuery(query, 'segments') as TCubeSegment[];
321
455
 
322
456
  const indexedMeasures = indexBy(prop('cubeName'), availableMembers.measures);
323
457
  const indexedDimensions = indexBy(prop('cubeName'), availableMembers.dimensions);
324
458
  const cubeNames = uniq([...Object.keys(indexedMeasures), ...Object.keys(indexedDimensions)]).sort();
325
459
 
326
- availableFilterMembers = cubeNames.map((name) => {
460
+ // Measures and dimensions of a cube are merged into one member list, which
461
+ // the declared type describes as either one or the other
462
+ availableFilterMembers = cubeNames.map((name): AvailableCube<TCubeMeasure | TCubeDimension> => {
327
463
  const cube = indexedMeasures[name] || indexedDimensions[name];
328
464
 
329
465
  return {
@@ -333,7 +469,7 @@ export default class QueryBuilder extends React.Component {
333
469
  ...indexedDimensions[name]?.members
334
470
  ].sort((a, b) => (a.shortTitle > b.shortTitle ? 1 : -1)),
335
471
  };
336
- });
472
+ }) as Array<AvailableCube<TCubeMeasure> | AvailableCube<TCubeDimension>>;
337
473
  }
338
474
 
339
475
  const activeOrder = Array.isArray(query.order) ? Object.fromEntries(query.order) : query.order;
@@ -357,7 +493,7 @@ export default class QueryBuilder extends React.Component {
357
493
  // This is needed so that when an order member becomes active, it doesn't jump to the top of the list
358
494
  orderMembers = (this.orderMembersOrderKeys || [])
359
495
  .map((id) => orderMembers.find((member) => member.id === id))
360
- .filter(Boolean);
496
+ .filter(Boolean) as TOrderMember[];
361
497
  }
362
498
 
363
499
  return {
@@ -367,12 +503,14 @@ export default class QueryBuilder extends React.Component {
367
503
  metaErrorStack,
368
504
  query,
369
505
  error: queryError, // Match same name as QueryRenderer prop
370
- validatedQuery,
506
+ validatedQuery: validatedQuery as Query,
371
507
  isQueryPresent: this.isQueryPresent(),
372
508
  chartType,
373
509
  measures,
374
510
  dimensions,
375
- timeDimensions,
511
+ // The declared granularity options require a `name`, which the
512
+ // "w/o grouping" option leaves out
513
+ timeDimensions: timeDimensions as (TimeDimensionWithExtraFields & { index: number })[],
376
514
  segments,
377
515
  filters,
378
516
  orderMembers,
@@ -383,21 +521,25 @@ export default class QueryBuilder extends React.Component {
383
521
  availableMembers,
384
522
  availableFilterMembers,
385
523
  updateQuery: (queryUpdate) => this.updateQuery(queryUpdate),
386
- updateMeasures: updateMethods('measures'),
387
- updateDimensions: updateMethods('dimensions'),
388
- updateSegments: updateMethods('segments'),
389
- updateTimeDimensions: updateMethods('timeDimensions', toTimeDimension),
390
- updateFilters: updateMethods('filters', toFilter),
391
- updateChartType: (newChartType) => this.updateVizState({ chartType: newChartType }),
524
+ updateMeasures: updateMethods<TCubeMeasure>('measures'),
525
+ updateDimensions: updateMethods<TCubeDimension>('dimensions'),
526
+ updateSegments: updateMethods<TCubeSegment>('segments'),
527
+ updateTimeDimensions: updateMethods<TimeDimensionUpdateInput>('timeDimensions', toTimeDimension) as
528
+ MemberUpdater<TimeDimensionRangedUpdateFields | TimeDimensionComparisonUpdateFields>,
529
+ updateFilters: updateMethods<FilterUpdateInput>('filters', toFilter) as MemberUpdater<FilterUpdateFields>,
530
+ updateChartType: (newChartType: ChartType) => this.updateVizState({ chartType: newChartType }),
392
531
  updateOrder: {
393
- set: (memberId, newOrder = 'asc') => {
532
+ set: (memberId: string, newOrder: QueryOrder | 'none' = 'asc') => {
394
533
  this.updateQuery({
395
534
  order: orderMembers
396
535
  .map((orderMember) => ({
397
536
  ...orderMember,
398
537
  order: orderMember.id === memberId ? newOrder : orderMember.order,
399
538
  }))
400
- .reduce((acc, { id, order }) => (order !== 'none' ? [...acc, [id, order]] : acc), []),
539
+ .reduce<[string, QueryOrder][]>(
540
+ (acc, { id, order }) => (order !== 'none' ? [...acc, [id, order]] : acc),
541
+ []
542
+ ),
401
543
  });
402
544
  },
403
545
  update: (order) => {
@@ -405,7 +547,7 @@ export default class QueryBuilder extends React.Component {
405
547
  order,
406
548
  });
407
549
  },
408
- reorder: (sourceIndex, destinationIndex) => {
550
+ reorder: (sourceIndex: number, destinationIndex: number) => {
409
551
  if (sourceIndex == null || destinationIndex == null) {
410
552
  return;
411
553
  }
@@ -414,15 +556,20 @@ export default class QueryBuilder extends React.Component {
414
556
  this.orderMembersOrderKeys = nextArray.map(({ id }) => id);
415
557
 
416
558
  this.updateQuery({
417
- order: nextArray.reduce((acc, { id, order }) => (order !== 'none' ? [...acc, [id, order]] : acc), []),
559
+ order: nextArray.reduce<[string, QueryOrder][]>(
560
+ (acc, { id, order }) => (order !== 'none' ? [...acc, [id, order]] : acc),
561
+ []
562
+ ),
418
563
  });
419
564
  },
420
565
  },
421
566
  pivotConfig,
422
567
  updatePivotConfig: {
423
- moveItem: ({ sourceIndex, destinationIndex, sourceAxis, destinationAxis }) => {
568
+ moveItem: ({ sourceIndex, destinationIndex, sourceAxis, destinationAxis }: PivotConfigUpdaterArgs) => {
424
569
  this.updateVizState({
425
- pivotConfig: movePivotItem(pivotConfig, sourceIndex, destinationIndex, sourceAxis, destinationAxis),
570
+ pivotConfig: movePivotItem(
571
+ pivotConfig as PivotConfig, sourceIndex, destinationIndex, sourceAxis, destinationAxis
572
+ ),
426
573
  });
427
574
  },
428
575
  update: (config) => {
@@ -440,12 +587,12 @@ export default class QueryBuilder extends React.Component {
440
587
  missingMembers,
441
588
  refresh: this.fetchMeta,
442
589
  isFetchingMeta,
443
- dryRunResponse,
590
+ dryRunResponse: dryRunResponse as DryRunResponse | undefined,
444
591
  ...queryRendererProps,
445
592
  };
446
593
  }
447
594
 
448
- updateQuery(queryUpdate) {
595
+ updateQuery(queryUpdate: Query) {
449
596
  const { query } = this.state;
450
597
 
451
598
  this.updateVizState({
@@ -456,7 +603,7 @@ export default class QueryBuilder extends React.Component {
456
603
  });
457
604
  }
458
605
 
459
- async updateVizState(state) {
606
+ async updateVizState(state: QueryBuilderStateUpdate) {
460
607
  const { setQuery, setVizState } = this.props;
461
608
  const { query: stateQuery, pivotConfig: statePivotConfig, chartType, meta } = this.state;
462
609
 
@@ -465,11 +612,11 @@ export default class QueryBuilder extends React.Component {
465
612
  finalState.query = { ...stateQuery };
466
613
  }
467
614
 
468
- let vizStateSent = null;
469
- const handleVizStateChange = (currentState) => {
615
+ let vizStateSent: QueryBuilderState | null = null;
616
+ const handleVizStateChange = (currentState: QueryBuilderStateUpdate) => {
470
617
  const { onVizStateChanged } = this.props;
471
618
  if (onVizStateChanged) {
472
- const newVizState = pick(['chartType', 'pivotConfig', 'query'], currentState);
619
+ const newVizState = pick(['chartType', 'pivotConfig', 'query'], currentState) as QueryBuilderState;
473
620
  // Don't run callbacks more than once unless the viz state has changed since last time
474
621
  if (!vizStateSent || !equals(vizStateSent, newVizState)) {
475
622
  onVizStateChanged(newVizState);
@@ -480,9 +627,9 @@ export default class QueryBuilder extends React.Component {
480
627
  };
481
628
 
482
629
  // deprecated, setters replaced by onVizStateChanged
483
- const runSetters = (currentState) => {
630
+ const runSetters = (currentState: QueryBuilderStateUpdate) => {
484
631
  if (setVizState) {
485
- setVizState(pick(['chartType', 'pivotConfig', 'query'], currentState));
632
+ setVizState(pick(['chartType', 'pivotConfig', 'query'], currentState) as QueryBuilderState);
486
633
  }
487
634
  if (currentState.query && setQuery) {
488
635
  setQuery(currentState.query);
@@ -494,8 +641,8 @@ export default class QueryBuilder extends React.Component {
494
641
  }
495
642
 
496
643
  finalState.pivotConfig = ResultSet.getNormalizedPivotConfig(
497
- finalState.query,
498
- finalState.pivotConfig !== undefined ? finalState.pivotConfig : statePivotConfig
644
+ finalState.query as PivotQuery,
645
+ (finalState.pivotConfig !== undefined ? finalState.pivotConfig : statePivotConfig) as PivotConfig | undefined
499
646
  );
500
647
 
501
648
  finalState.missingMembers = this.getMissingMembers(finalState.query, meta);
@@ -511,7 +658,7 @@ export default class QueryBuilder extends React.Component {
511
658
  this.setState({
512
659
  ...finalState,
513
660
  queryError: null,
514
- });
661
+ } as QueryBuilderInternalState);
515
662
 
516
663
  handleVizStateChange(finalState);
517
664
 
@@ -542,32 +689,34 @@ export default class QueryBuilder extends React.Component {
542
689
  });
543
690
  }
544
691
  } catch (error) {
692
+ const requestError = error as RequestError;
693
+
545
694
  this.setState({
546
- queryError: new Error(error.response?.plainError || error.message),
547
- richQueryError: new Error(error.message || error.toString())
695
+ queryError: new Error(requestError.response?.plainError || requestError.message),
696
+ richQueryError: new Error(requestError.message || requestError.toString())
548
697
  });
549
698
  }
550
699
  }
551
700
 
552
- this.setState(finalState, () => handleVizStateChange(this.state));
701
+ this.setState(finalState as QueryBuilderInternalState, () => handleVizStateChange(this.state));
553
702
  }
554
703
 
555
- validatedQuery(state) {
704
+ validatedQuery(state?: QueryBuilderStateUpdate) {
556
705
  const { query } = state || this.state;
557
706
 
558
707
  return validateQuery(query);
559
708
  }
560
709
 
561
- defaultHeuristics(newState) {
710
+ defaultHeuristics(newState: QueryBuilderStateUpdate): QueryBuilderStateUpdate {
562
711
  const { query, sessionGranularity, meta } = this.state;
563
712
 
564
- return defaultHeuristics(newState, query, {
565
- meta,
713
+ return defaultHeuristics(newState as TDefaultHeuristicsState, query, {
714
+ meta: meta as Meta,
566
715
  sessionGranularity: sessionGranularity || 'day',
567
- });
716
+ }) as QueryBuilderStateUpdate;
568
717
  }
569
718
 
570
- applyStateChangeHeuristics(newState) {
719
+ applyStateChangeHeuristics(newState: QueryBuilderStateUpdate): QueryBuilderStateUpdate {
571
720
  const { stateChangeHeuristics, disableHeuristics } = this.props;
572
721
  if (disableHeuristics) {
573
722
  return newState;