@finos/legend-query-builder 4.14.25 → 4.14.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. package/lib/components/QueryBuilderConstantExpressionPanel.d.ts.map +1 -1
  2. package/lib/components/QueryBuilderConstantExpressionPanel.js +20 -8
  3. package/lib/components/QueryBuilderConstantExpressionPanel.js.map +1 -1
  4. package/lib/components/QueryBuilderParametersPanel.d.ts.map +1 -1
  5. package/lib/components/QueryBuilderParametersPanel.js +18 -14
  6. package/lib/components/QueryBuilderParametersPanel.js.map +1 -1
  7. package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts +4 -0
  8. package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -1
  9. package/lib/components/result/tds/QueryBuilderTDSGridResult.js +126 -37
  10. package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -1
  11. package/lib/components/shared/BasicValueSpecificationEditor.d.ts +2 -2
  12. package/lib/components/shared/BasicValueSpecificationEditor.d.ts.map +1 -1
  13. package/lib/components/shared/BasicValueSpecificationEditor.js +12 -11
  14. package/lib/components/shared/BasicValueSpecificationEditor.js.map +1 -1
  15. package/lib/index.css +2 -2
  16. package/lib/index.css.map +1 -1
  17. package/lib/package.json +1 -1
  18. package/lib/stores/QueryBuilderResultState.d.ts +12 -0
  19. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  20. package/lib/stores/QueryBuilderResultState.js +68 -4
  21. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  22. package/package.json +5 -5
  23. package/src/components/QueryBuilderConstantExpressionPanel.tsx +37 -21
  24. package/src/components/QueryBuilderParametersPanel.tsx +14 -9
  25. package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +188 -11
  26. package/src/components/shared/BasicValueSpecificationEditor.tsx +69 -49
  27. package/src/stores/QueryBuilderResultState.ts +82 -4
@@ -14,11 +14,10 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { clsx } from '@finos/legend-art';
18
17
  import { observer } from 'mobx-react-lite';
19
18
  import type { QueryBuilderState } from '../../../stores/QueryBuilderState.js';
20
19
  import { PRIMITIVE_TYPE, type TDSExecutionResult } from '@finos/legend-graph';
21
- import { useState, useCallback } from 'react';
20
+ import { useState, useCallback, useEffect } from 'react';
22
21
  import {
23
22
  DataGrid,
24
23
  type DataGridApi,
@@ -28,23 +27,45 @@ import {
28
27
  type DataGridGetContextMenuItemsParams,
29
28
  type DataGridIRowNode,
30
29
  type DataGridMenuItemDef,
30
+ type DataGridIAggFuncParams,
31
31
  } from '@finos/legend-lego/data-grid';
32
32
  import {
33
33
  getRowDataFromExecutionResult,
34
34
  type IQueryRendererParamsWithGridType,
35
35
  filterByOrOutValues,
36
36
  } from './QueryBuilderTDSResultShared.js';
37
- import type {
38
- QueryBuilderResultState,
39
- QueryBuilderTDSResultCellData,
40
- QueryBuilderTDSResultCellDataType,
41
- QueryBuilderTDSRowDataType,
37
+ import {
38
+ type QueryBuilderResultState,
39
+ QueryBuilderResultWavgAggregationState,
40
+ type QueryBuilderTDSResultCellData,
41
+ type QueryBuilderTDSResultCellDataType,
42
+ type QueryBuilderTDSRowDataType,
42
43
  } from '../../../stores/QueryBuilderResultState.js';
43
44
  import { QueryBuilderTDSState } from '../../../stores/fetch-structure/tds/QueryBuilderTDSState.js';
44
45
  import { DEFAULT_LOCALE } from '../../../graph-manager/QueryBuilderConst.js';
45
- import { isNumber, isString, isValidURL } from '@finos/legend-shared';
46
+ import {
47
+ assertErrorThrown,
48
+ isNumber,
49
+ isString,
50
+ isValidURL,
51
+ } from '@finos/legend-shared';
46
52
  import { useApplicationStore } from '@finos/legend-application';
47
53
  import { QUERY_BUILDER_TEST_ID } from '../../../__lib__/QueryBuilderTesting.js';
54
+ import {
55
+ clsx,
56
+ Modal,
57
+ ModalBody,
58
+ ModalHeader,
59
+ ModalFooter,
60
+ ModalFooterButton,
61
+ Dialog,
62
+ CustomSelectorInput,
63
+ } from '@finos/legend-art';
64
+
65
+ export const enum QueryBuilderDataGridCustomAggregationFunction {
66
+ wavg = 'wavg',
67
+ WAVG = 'WAVG',
68
+ }
48
69
 
49
70
  const getAggregationTDSColumnCustomizations = (
50
71
  result: TDSExecutionResult,
@@ -71,7 +92,7 @@ const getAggregationTDSColumnCustomizations = (
71
92
  case PRIMITIVE_TYPE.FLOAT:
72
93
  return {
73
94
  filter: 'agNumberColumnFilter',
74
- allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg'],
95
+ allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
75
96
  };
76
97
  default:
77
98
  return {
@@ -222,16 +243,19 @@ export const QueryBuilderTDSGridResult = observer(
222
243
  }) => {
223
244
  const { executionResult, queryBuilderState } = props;
224
245
  const applicationStore = useApplicationStore();
246
+ const darkMode =
247
+ !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled;
225
248
  const [columnAPi, setColumnApi] = useState<DataGridColumnApi | undefined>(
226
249
  undefined,
227
250
  );
251
+ const [aggFuncParams, setAggFuncParams] = useState<
252
+ DataGridIAggFuncParams | undefined
253
+ >(undefined);
228
254
  const resultState = queryBuilderState.resultState;
229
255
  const isLocalModeEnabled = queryBuilderState.isLocalModeEnabled;
230
256
  const colDefs = isLocalModeEnabled
231
257
  ? getLocalColDefs(executionResult, resultState)
232
258
  : getColDefs(executionResult, resultState);
233
- const darkMode =
234
- !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled;
235
259
 
236
260
  const onSaveGridColumnState = (): void => {
237
261
  if (!columnAPi) {
@@ -242,6 +266,10 @@ export const QueryBuilderTDSGridResult = observer(
242
266
  isPivotModeEnabled: columnAPi.isPivotMode(),
243
267
  isLocalModeEnabled: true,
244
268
  previewLimit: resultState.previewLimit,
269
+ ...(resultState.wavgAggregationState?.weightedColumnIdPairs && {
270
+ weightedColumnPairs:
271
+ resultState.wavgAggregationState.weightedColumnIdPairs,
272
+ }),
245
273
  });
246
274
  };
247
275
 
@@ -336,6 +364,103 @@ export const QueryBuilderTDSGridResult = observer(
336
364
  ],
337
365
  );
338
366
 
367
+ const weightedColumnOptions = columnAPi
368
+ ?.getColumns()
369
+ ?.filter((c) => c.getColDef().cellDataType === 'number')
370
+ .map((col) => ({
371
+ label: col.getColId(),
372
+ value: col.getColId(),
373
+ }));
374
+
375
+ const selectedWeightedColumn =
376
+ aggFuncParams?.colDef.field &&
377
+ resultState.wavgAggregationState?.weightedColumnIdPairs.get(
378
+ aggFuncParams.colDef.field,
379
+ )
380
+ ? {
381
+ label: resultState.wavgAggregationState.weightedColumnIdPairs.get(
382
+ aggFuncParams.colDef.field,
383
+ ),
384
+ value: resultState.wavgAggregationState.weightedColumnIdPairs.get(
385
+ aggFuncParams.colDef.field,
386
+ ),
387
+ }
388
+ : null;
389
+
390
+ const onWeightedColumnOptionChange = async (
391
+ option: { label: string; value: string } | null,
392
+ ): Promise<void> => {
393
+ if (aggFuncParams?.colDef.field && option?.value) {
394
+ resultState.wavgAggregationState?.addWeightedColumnIdPair(
395
+ aggFuncParams.colDef.field,
396
+ option.value,
397
+ );
398
+ }
399
+ };
400
+
401
+ const weightedAverage = (param: DataGridIAggFuncParams): void => {
402
+ if (param.colDef.field) {
403
+ if (!resultState.wavgAggregationState) {
404
+ resultState.setWavgAggregationState(
405
+ new QueryBuilderResultWavgAggregationState(),
406
+ );
407
+ }
408
+ resultState.wavgAggregationState?.addWeightedColumnIdPair(
409
+ param.colDef.field,
410
+ param.colDef.field,
411
+ );
412
+ resultState.wavgAggregationState?.setIsApplyingWavg(true);
413
+ setAggFuncParams(param);
414
+ } else {
415
+ applicationStore.notificationService.notifyError(
416
+ 'The id of this column can`t be retrieved to perform weighted average',
417
+ );
418
+ }
419
+ };
420
+
421
+ const weightedAverageHelper = (param: DataGridIAggFuncParams): number => {
422
+ try {
423
+ const column = param.colDef.field;
424
+ if (column) {
425
+ const weightedColumnId =
426
+ resultState.wavgAggregationState?.weightedColumnIdPairs.get(column);
427
+ if (weightedColumnId) {
428
+ const weightedColumnSum = param.rowNode.allLeafChildren
429
+ .map((node) => node.data[weightedColumnId])
430
+ .reduce((a, b) => a + b) as number;
431
+ const weightedColumnMultiply = param.rowNode.allLeafChildren
432
+ .map((node) => node.data[weightedColumnId] * node.data[column])
433
+ .reduce((a, b) => a + b);
434
+ if (weightedColumnSum !== 0) {
435
+ onSaveGridColumnState();
436
+ return weightedColumnMultiply / weightedColumnSum;
437
+ } else {
438
+ applicationStore.notificationService.notifyError(
439
+ 'The weighted column sum is 0',
440
+ );
441
+ }
442
+ } else {
443
+ applicationStore.notificationService.notifyError(
444
+ 'The weighted column Id is not defined',
445
+ );
446
+ }
447
+ }
448
+ } catch (error) {
449
+ assertErrorThrown(error);
450
+ applicationStore.notificationService.notifyError(error);
451
+ }
452
+ return -1;
453
+ };
454
+
455
+ useEffect(() => {
456
+ if (aggFuncParams) {
457
+ aggFuncParams.columnApi.setColumnAggFunc(
458
+ aggFuncParams.colDef.field!,
459
+ QueryBuilderDataGridCustomAggregationFunction.WAVG,
460
+ );
461
+ }
462
+ }, [resultState.wavgAggregationState, aggFuncParams]);
463
+
339
464
  return (
340
465
  <div
341
466
  data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_VALUES_TDS}
@@ -372,6 +497,10 @@ export const QueryBuilderTDSGridResult = observer(
372
497
  suppressFieldDotNotation={true}
373
498
  suppressContextMenu={false}
374
499
  columnDefs={colDefs}
500
+ aggFuncs={{
501
+ wavg: weightedAverage,
502
+ WAVG: weightedAverageHelper,
503
+ }}
375
504
  sideBar={['columns', 'filters']}
376
505
  onColumnVisible={onSaveGridColumnState}
377
506
  onColumnPinned={onSaveGridColumnState}
@@ -411,6 +540,54 @@ export const QueryBuilderTDSGridResult = observer(
411
540
  }
412
541
  />
413
542
  )}
543
+ {resultState.wavgAggregationState?.isApplyingWavg && (
544
+ <Dialog
545
+ open={resultState.wavgAggregationState.isApplyingWavg}
546
+ onClose={() =>
547
+ resultState.wavgAggregationState?.setIsApplyingWavg(false)
548
+ }
549
+ classes={{
550
+ root: 'editor-modal__root-container',
551
+ container: 'editor-modal__container',
552
+ paper: 'editor-modal__content',
553
+ }}
554
+ >
555
+ <Modal
556
+ darkMode={
557
+ !applicationStore.layoutService
558
+ .TEMPORARY__isLightColorThemeEnabled
559
+ }
560
+ className="query-editor__blocking-alert"
561
+ >
562
+ <ModalHeader title="Applying Weighted Average" />
563
+ <ModalBody>
564
+ <div className="query-builder__result__tds-grid__text">
565
+ choose a weighted column from dropdown
566
+ </div>
567
+ <CustomSelectorInput
568
+ options={weightedColumnOptions}
569
+ onChange={onWeightedColumnOptionChange}
570
+ value={selectedWeightedColumn}
571
+ placeholder={'Choose a weighted column'}
572
+ darkMode={
573
+ !applicationStore.layoutService
574
+ .TEMPORARY__isLightColorThemeEnabled
575
+ }
576
+ />
577
+ </ModalBody>
578
+ <ModalFooter>
579
+ <ModalFooterButton
580
+ onClick={() => {
581
+ resultState.wavgAggregationState?.setIsApplyingWavg(
582
+ false,
583
+ );
584
+ }}
585
+ text="Apply"
586
+ />
587
+ </ModalFooter>
588
+ </Modal>
589
+ </Dialog>
590
+ )}
414
591
  </div>
415
592
  </div>
416
593
  );
@@ -70,7 +70,13 @@ import {
70
70
  } from '@finos/legend-shared';
71
71
  import { flowResult } from 'mobx';
72
72
  import { observer } from 'mobx-react-lite';
73
- import { useEffect, useRef, useState } from 'react';
73
+ import {
74
+ forwardRef,
75
+ useEffect,
76
+ useImperativeHandle,
77
+ useRef,
78
+ useState,
79
+ } from 'react';
74
80
  import {
75
81
  instanceValue_setValue,
76
82
  instanceValue_setValues,
@@ -204,23 +210,26 @@ const VariableExpressionParameterEditor = observer(
204
210
  );
205
211
 
206
212
  const StringPrimitiveInstanceValueEditor = observer(
207
- (props: {
208
- valueSpecification: PrimitiveInstanceValue;
209
- className?: string | undefined;
210
- setValueSpecification: (val: ValueSpecification) => void;
211
- resetValue: () => void;
212
- selectorConfig?:
213
- | {
214
- values: string[] | undefined;
215
- isLoading: boolean;
216
- reloadValues:
217
- | DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
218
- | undefined;
219
- cleanUpReloadValues?: () => void;
220
- }
221
- | undefined;
222
- obseverContext: ObserverContext;
223
- }) => {
213
+ forwardRef<
214
+ HTMLInputElement,
215
+ {
216
+ valueSpecification: PrimitiveInstanceValue;
217
+ className?: string | undefined;
218
+ setValueSpecification: (val: ValueSpecification) => void;
219
+ resetValue: () => void;
220
+ selectorConfig?:
221
+ | {
222
+ values: string[] | undefined;
223
+ isLoading: boolean;
224
+ reloadValues:
225
+ | DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
226
+ | undefined;
227
+ cleanUpReloadValues?: () => void;
228
+ }
229
+ | undefined;
230
+ obseverContext: ObserverContext;
231
+ }
232
+ >(function StringPrimitiveInstanceValueEditor(props, ref) {
224
233
  const {
225
234
  valueSpecification,
226
235
  className,
@@ -307,6 +316,7 @@ const StringPrimitiveInstanceValueEditor = observer(
307
316
  value={value}
308
317
  placeholder={value === '' ? '(empty)' : undefined}
309
318
  onChange={changeInputValue}
319
+ ref={ref}
310
320
  />
311
321
  )}
312
322
  <button
@@ -319,7 +329,7 @@ const StringPrimitiveInstanceValueEditor = observer(
319
329
  </button>
320
330
  </div>
321
331
  );
322
- },
332
+ }),
323
333
  );
324
334
 
325
335
  const BooleanPrimitiveInstanceValueEditor = observer(
@@ -367,14 +377,17 @@ const BooleanPrimitiveInstanceValueEditor = observer(
367
377
  );
368
378
 
369
379
  const NumberPrimitiveInstanceValueEditor = observer(
370
- (props: {
371
- valueSpecification: PrimitiveInstanceValue;
372
- isInteger: boolean;
373
- className?: string | undefined;
374
- resetValue: () => void;
375
- setValueSpecification: (val: ValueSpecification) => void;
376
- obseverContext: ObserverContext;
377
- }) => {
380
+ forwardRef<
381
+ HTMLInputElement,
382
+ {
383
+ valueSpecification: PrimitiveInstanceValue;
384
+ isInteger: boolean;
385
+ className?: string | undefined;
386
+ resetValue: () => void;
387
+ setValueSpecification: (val: ValueSpecification) => void;
388
+ obseverContext: ObserverContext;
389
+ }
390
+ >(function NumberPrimitiveInstanceValueEditor(props, ref) {
378
391
  const {
379
392
  valueSpecification,
380
393
  isInteger,
@@ -387,6 +400,7 @@ const NumberPrimitiveInstanceValueEditor = observer(
387
400
  (valueSpecification.values[0] as number).toString(),
388
401
  );
389
402
  const inputRef = useRef<HTMLInputElement>(null);
403
+ useImperativeHandle(ref, () => inputRef.current as HTMLInputElement, []);
390
404
  const numericValue = isInteger
391
405
  ? Number.parseInt(Number(value).toString(), 10)
392
406
  : Number(value);
@@ -484,7 +498,7 @@ const NumberPrimitiveInstanceValueEditor = observer(
484
498
  </button>
485
499
  </div>
486
500
  );
487
- },
501
+ }),
488
502
  );
489
503
 
490
504
  const EnumValueInstanceValueEditor = observer(
@@ -947,26 +961,29 @@ const DateInstanceValueEditor = observer(
947
961
  *
948
962
  * See https://github.com/finos/legend-studio/pull/1021
949
963
  */
950
- export const BasicValueSpecificationEditor: React.FC<{
951
- valueSpecification: ValueSpecification;
952
- graph: PureModel;
953
- obseverContext: ObserverContext;
954
- typeCheckOption: TypeCheckOption;
955
- className?: string | undefined;
956
- setValueSpecification: (val: ValueSpecification) => void;
957
- resetValue: () => void;
958
- isConstant?: boolean;
959
- selectorConfig?:
960
- | {
961
- values: string[] | undefined;
962
- isLoading: boolean;
963
- reloadValues:
964
- | DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
965
- | undefined;
966
- cleanUpReloadValues?: () => void;
967
- }
968
- | undefined;
969
- }> = (props) => {
964
+ export const BasicValueSpecificationEditor = forwardRef<
965
+ HTMLInputElement,
966
+ {
967
+ valueSpecification: ValueSpecification;
968
+ graph: PureModel;
969
+ obseverContext: ObserverContext;
970
+ typeCheckOption: TypeCheckOption;
971
+ className?: string | undefined;
972
+ setValueSpecification: (val: ValueSpecification) => void;
973
+ resetValue: () => void;
974
+ isConstant?: boolean;
975
+ selectorConfig?:
976
+ | {
977
+ values: string[] | undefined;
978
+ isLoading: boolean;
979
+ reloadValues:
980
+ | DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
981
+ | undefined;
982
+ cleanUpReloadValues?: () => void;
983
+ }
984
+ | undefined;
985
+ }
986
+ >(function BasicValueSpecificationEditor(props, ref) {
970
987
  const {
971
988
  className,
972
989
  valueSpecification,
@@ -990,6 +1007,7 @@ export const BasicValueSpecificationEditor: React.FC<{
990
1007
  resetValue={resetValue}
991
1008
  selectorConfig={selectorConfig}
992
1009
  obseverContext={obseverContext}
1010
+ ref={ref}
993
1011
  />
994
1012
  );
995
1013
  case PRIMITIVE_TYPE.BOOLEAN:
@@ -1016,6 +1034,7 @@ export const BasicValueSpecificationEditor: React.FC<{
1016
1034
  className={className}
1017
1035
  resetValue={resetValue}
1018
1036
  obseverContext={obseverContext}
1037
+ ref={ref}
1019
1038
  />
1020
1039
  );
1021
1040
  case PRIMITIVE_TYPE.DATE:
@@ -1134,6 +1153,7 @@ export const BasicValueSpecificationEditor: React.FC<{
1134
1153
  className={className}
1135
1154
  resetValue={resetValue}
1136
1155
  obseverContext={obseverContext}
1156
+ ref={ref}
1137
1157
  />
1138
1158
  );
1139
1159
  }
@@ -1141,4 +1161,4 @@ export const BasicValueSpecificationEditor: React.FC<{
1141
1161
  }
1142
1162
 
1143
1163
  return <UnsupportedValueSpecificationEditor />;
1144
- };
1164
+ });
@@ -48,6 +48,7 @@ import { QUERY_BUILDER_EVENT } from '../__lib__/QueryBuilderEvent.js';
48
48
  import { ExecutionPlanState } from './execution-plan/ExecutionPlanState.js';
49
49
  import type { DataGridColumnState } from '@finos/legend-lego/data-grid';
50
50
  import { downloadStream } from '@finos/legend-application';
51
+ import { QueryBuilderDataGridCustomAggregationFunction } from '../components/result/tds/QueryBuilderTDSGridResult.js';
51
52
 
52
53
  export const DEFAULT_LIMIT = 1000;
53
54
 
@@ -83,8 +84,37 @@ type QueryBuilderDataGridConfig = {
83
84
  isPivotModeEnabled: boolean | undefined;
84
85
  isLocalModeEnabled: boolean | undefined;
85
86
  previewLimit?: number | undefined;
87
+ weightedColumnPairs?: Map<string, string> | undefined;
86
88
  };
87
89
 
90
+ export class QueryBuilderResultWavgAggregationState {
91
+ isApplyingWavg = false;
92
+ weightedColumnIdPairs: Map<string, string>;
93
+
94
+ constructor() {
95
+ makeObservable(this, {
96
+ isApplyingWavg: observable,
97
+ weightedColumnIdPairs: observable,
98
+ setIsApplyingWavg: action,
99
+ addWeightedColumnIdPair: action,
100
+ removeWeightedColumnIdPair: action,
101
+ });
102
+ this.weightedColumnIdPairs = new Map<string, string>();
103
+ }
104
+
105
+ setIsApplyingWavg(val: boolean): void {
106
+ this.isApplyingWavg = val;
107
+ }
108
+
109
+ addWeightedColumnIdPair(col: string, weightedColumnId: string): void {
110
+ this.weightedColumnIdPairs.set(col, weightedColumnId);
111
+ }
112
+
113
+ removeWeightedColumnIdPair(col: string): void {
114
+ this.weightedColumnIdPairs.delete(col);
115
+ }
116
+ }
117
+
88
118
  export class QueryBuilderResultState {
89
119
  readonly queryBuilderState: QueryBuilderState;
90
120
  readonly executionPlanState: ExecutionPlanState;
@@ -105,6 +135,7 @@ export class QueryBuilderResultState {
105
135
  isSelectingCells: boolean;
106
136
 
107
137
  gridConfig: QueryBuilderDataGridConfig | undefined;
138
+ wavgAggregationState: QueryBuilderResultWavgAggregationState | undefined;
108
139
 
109
140
  constructor(queryBuilderState: QueryBuilderState) {
110
141
  makeObservable(this, {
@@ -120,7 +151,9 @@ export class QueryBuilderResultState {
120
151
  isSelectingCells: observable,
121
152
  isQueryUsageViewerOpened: observable,
122
153
  gridConfig: observable,
154
+ wavgAggregationState: observable,
123
155
  setGridConfig: action,
156
+ setWavgAggregationState: action,
124
157
  setIsSelectingCells: action,
125
158
  setIsRunningQuery: action,
126
159
  setExecutionResult: action,
@@ -153,6 +186,12 @@ export class QueryBuilderResultState {
153
186
  this.gridConfig = val;
154
187
  }
155
188
 
189
+ setWavgAggregationState(
190
+ val: QueryBuilderResultWavgAggregationState | undefined,
191
+ ): void {
192
+ this.wavgAggregationState = val;
193
+ }
194
+
156
195
  setIsSelectingCells(val: boolean): void {
157
196
  this.isSelectingCells = val;
158
197
  }
@@ -199,11 +238,50 @@ export class QueryBuilderResultState {
199
238
  }
200
239
  }
201
240
 
241
+ processWeightedColumnPairsMap(
242
+ config: QueryGridConfig,
243
+ ): Map<string, string> | undefined {
244
+ if (config.weightedColumnPairs) {
245
+ const wavgColumns = config.columns
246
+ .filter(
247
+ (col) =>
248
+ (col as DataGridColumnState).aggFunc ===
249
+ QueryBuilderDataGridCustomAggregationFunction.WAVG,
250
+ )
251
+ .map((col) => (col as DataGridColumnState).colId);
252
+ const weightedColumnPairsMap = new Map<string, string>();
253
+ config.weightedColumnPairs.forEach((wc) => {
254
+ if (wc[0] && wc[1]) {
255
+ weightedColumnPairsMap.set(wc[0], wc[1]);
256
+ }
257
+ });
258
+ for (const wavgCol of weightedColumnPairsMap.keys()) {
259
+ if (!wavgColumns.includes(wavgCol)) {
260
+ weightedColumnPairsMap.delete(wavgCol);
261
+ }
262
+ }
263
+ return weightedColumnPairsMap;
264
+ }
265
+ return undefined;
266
+ }
267
+
202
268
  handlePreConfiguredGridConfig(config: QueryGridConfig): void {
203
- const newConfig = {
204
- ...config,
205
- columns: config.columns as DataGridColumnState[],
206
- };
269
+ let newConfig;
270
+ const weightedColumnPairsMap = this.processWeightedColumnPairsMap(config);
271
+ if (weightedColumnPairsMap) {
272
+ this.wavgAggregationState = new QueryBuilderResultWavgAggregationState();
273
+ this.wavgAggregationState.weightedColumnIdPairs = weightedColumnPairsMap;
274
+ newConfig = {
275
+ ...config,
276
+ weightedColumnPairs: weightedColumnPairsMap,
277
+ columns: config.columns as DataGridColumnState[],
278
+ };
279
+ } else {
280
+ newConfig = {
281
+ ...config,
282
+ columns: config.columns as DataGridColumnState[],
283
+ };
284
+ }
207
285
  if (config.previewLimit) {
208
286
  this.setPreviewLimit(config.previewLimit);
209
287
  }