@finos/legend-query-builder 4.7.1 → 4.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. package/lib/__lib__/QueryBuilderTesting.d.ts +1 -0
  2. package/lib/__lib__/QueryBuilderTesting.d.ts.map +1 -1
  3. package/lib/__lib__/QueryBuilderTesting.js +1 -0
  4. package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
  5. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  6. package/lib/components/QueryBuilderResultPanel.js +14 -23
  7. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  8. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  9. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +5 -4
  10. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  11. package/lib/graph-manager/QueryBuilderConst.d.ts +1 -0
  12. package/lib/graph-manager/QueryBuilderConst.d.ts.map +1 -1
  13. package/lib/graph-manager/QueryBuilderConst.js +1 -0
  14. package/lib/graph-manager/QueryBuilderConst.js.map +1 -1
  15. package/lib/index.css +17 -1
  16. package/lib/index.css.map +1 -1
  17. package/lib/package.json +9 -9
  18. package/lib/stores/QueryBuilderResultState.d.ts +9 -9
  19. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  20. package/lib/stores/QueryBuilderResultState.js +20 -20
  21. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  22. package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.d.ts +1 -0
  23. package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.d.ts.map +1 -1
  24. package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.js +6 -0
  25. package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.js.map +1 -1
  26. package/lib/stores/milestoning/QueryBuilderBitemporalMilestoningImplementation.d.ts.map +1 -1
  27. package/lib/stores/milestoning/QueryBuilderBitemporalMilestoningImplementation.js +2 -0
  28. package/lib/stores/milestoning/QueryBuilderBitemporalMilestoningImplementation.js.map +1 -1
  29. package/lib/stores/milestoning/QueryBuilderBusinessTemporalMilestoningImplementation.d.ts.map +1 -1
  30. package/lib/stores/milestoning/QueryBuilderBusinessTemporalMilestoningImplementation.js +2 -0
  31. package/lib/stores/milestoning/QueryBuilderBusinessTemporalMilestoningImplementation.js.map +1 -1
  32. package/lib/stores/milestoning/QueryBuilderMilestoningState.d.ts.map +1 -1
  33. package/lib/stores/milestoning/QueryBuilderMilestoningState.js +0 -2
  34. package/lib/stores/milestoning/QueryBuilderMilestoningState.js.map +1 -1
  35. package/lib/stores/milestoning/QueryBuilderProcessingTemporalMilestoningImplementation.d.ts.map +1 -1
  36. package/lib/stores/milestoning/QueryBuilderProcessingTemporalMilestoningImplementation.js +2 -0
  37. package/lib/stores/milestoning/QueryBuilderProcessingTemporalMilestoningImplementation.js.map +1 -1
  38. package/package.json +17 -17
  39. package/src/__lib__/QueryBuilderTesting.ts +1 -0
  40. package/src/components/QueryBuilderResultPanel.tsx +34 -46
  41. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +86 -28
  42. package/src/graph-manager/QueryBuilderConst.ts +2 -0
  43. package/src/stores/QueryBuilderResultState.ts +20 -22
  44. package/src/stores/fetch-structure/tds/QueryResultSetModifierState.ts +7 -0
  45. package/src/stores/milestoning/QueryBuilderBitemporalMilestoningImplementation.ts +2 -0
  46. package/src/stores/milestoning/QueryBuilderBusinessTemporalMilestoningImplementation.ts +2 -0
  47. package/src/stores/milestoning/QueryBuilderMilestoningState.ts +0 -2
  48. package/src/stores/milestoning/QueryBuilderProcessingTemporalMilestoningImplementation.ts +2 -0
@@ -39,7 +39,6 @@ import {
39
39
  PanelDivider,
40
40
  } from '@finos/legend-art';
41
41
  import { format as formatSQL } from 'sql-formatter';
42
-
43
42
  import { observer } from 'mobx-react-lite';
44
43
  import { flowResult } from 'mobx';
45
44
  import type { QueryBuilderState } from '../stores/QueryBuilderState.js';
@@ -99,6 +98,7 @@ import { QUERY_BUILDER_TEST_ID } from '../__lib__/QueryBuilderTesting.js';
99
98
  import {
100
99
  DataGrid,
101
100
  type DataGridCellRendererParams,
101
+ type DataGridColumnDefinition,
102
102
  } from '@finos/legend-lego/data-grid';
103
103
  import {
104
104
  CODE_EDITOR_LANGUAGE,
@@ -115,6 +115,7 @@ import {
115
115
  QueryBuilderPostFilterOperator_IsNotEmpty,
116
116
  } from '../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.js';
117
117
  import { QueryUsageViewer } from './QueryUsageViewer.js';
118
+ import { DEFAULT_LOCALE } from '../graph-manager/QueryBuilderConst.js';
118
119
 
119
120
  export const tryToFormatSql = (sql: string): string => {
120
121
  try {
@@ -479,8 +480,15 @@ const QueryResultCellRenderer = observer(
479
480
  (params: IQueryRendererParamsWithGridType) => {
480
481
  const resultState = params.resultState;
481
482
  const tdsExecutionResult = params.tdsExecutionResult;
483
+ const fetchStructureImplementation =
484
+ resultState.queryBuilderState.fetchStructureState.implementation;
482
485
 
483
486
  const cellValue = params.value as string;
487
+ const formattedCellValue = !isNaN(Number(cellValue))
488
+ ? Intl.NumberFormat(DEFAULT_LOCALE, { maximumFractionDigits: 4 }).format(
489
+ Number(cellValue),
490
+ )
491
+ : cellValue;
484
492
  const columnName = params.column?.getColId() ?? '';
485
493
 
486
494
  const findCoordinatesFromResultValue = (
@@ -498,7 +506,6 @@ const QueryResultCellRenderer = observer(
498
506
  columnName,
499
507
  params.rowIndex,
500
508
  );
501
-
502
509
  const cellInFilteredResults = resultState.selectedCells.some(
503
510
  (result) =>
504
511
  result.coordinates.colIndex === currentCellCoordinates.colIndex &&
@@ -564,7 +571,7 @@ const QueryResultCellRenderer = observer(
564
571
  coordinates.rowIndex,
565
572
  coordinates.colIndex,
566
573
  ]);
567
- resultState.addCellData({
574
+ resultState.addSelectedCell({
568
575
  value: actualValue,
569
576
  columnName: columnName,
570
577
  coordinates: coordinates,
@@ -583,9 +590,6 @@ const QueryResultCellRenderer = observer(
583
590
  coordinates.rowIndex,
584
591
  coordinates.colIndex,
585
592
  ]);
586
-
587
- const rowNode = params.api.getRowNode(params.rowIndex.toString());
588
-
589
593
  resultState.setSelectedCells([
590
594
  {
591
595
  value: actualValue,
@@ -593,15 +597,6 @@ const QueryResultCellRenderer = observer(
593
597
  coordinates: coordinates,
594
598
  },
595
599
  ]);
596
-
597
- if (rowNode) {
598
- params.api.refreshCells({
599
- force: true,
600
- columns: [columnName],
601
- rowNodes: [rowNode],
602
- });
603
- }
604
-
605
600
  resultState.setMouseOverCell(resultState.selectedCells[0] ?? null);
606
601
  }
607
602
 
@@ -616,7 +611,6 @@ const QueryResultCellRenderer = observer(
616
611
  coordinates.rowIndex,
617
612
  coordinates.colIndex,
618
613
  ]);
619
-
620
614
  resultState.setSelectedCells([
621
615
  {
622
616
  value: actualValue,
@@ -624,19 +618,11 @@ const QueryResultCellRenderer = observer(
624
618
  coordinates: coordinates,
625
619
  },
626
620
  ]);
627
- const rowNode = params.api.getRowNode(params.rowIndex.toString());
628
-
629
- if (rowNode) {
630
- params.api.refreshCells({
631
- force: true,
632
- columns: [columnName],
633
- rowNodes: [rowNode],
634
- });
635
- }
636
621
  resultState.setMouseOverCell(resultState.selectedCells[0] ?? null);
637
622
  }
638
623
  }
639
624
  };
625
+
640
626
  const mouseUp: React.MouseEventHandler = (event) => {
641
627
  resultState.setIsSelectingCells(false);
642
628
  };
@@ -684,7 +670,7 @@ const QueryResultCellRenderer = observer(
684
670
  result.coordinates.rowIndex === x,
685
671
  )
686
672
  ) {
687
- resultState.addCellData(valueAndColumnId);
673
+ resultState.addSelectedCell(valueAndColumnId);
688
674
  }
689
675
  }
690
676
  }
@@ -693,9 +679,6 @@ const QueryResultCellRenderer = observer(
693
679
  resultState.setMouseOverCell(resultState.selectedCells[0] ?? null);
694
680
  };
695
681
 
696
- const fetchStructureImplementation =
697
- resultState.queryBuilderState.fetchStructureState.implementation;
698
-
699
682
  return (
700
683
  <ContextMenu
701
684
  content={
@@ -716,7 +699,6 @@ const QueryResultCellRenderer = observer(
716
699
  !resultState.mousedOverCell
717
700
  }
718
701
  menuProps={{ elevation: 7 }}
719
- key={params.value as string}
720
702
  className={clsx('ag-theme-balham-dark query-builder__result__tds-grid')}
721
703
  >
722
704
  <div
@@ -733,7 +715,7 @@ const QueryResultCellRenderer = observer(
733
715
  {cellValue}
734
716
  </a>
735
717
  ) : (
736
- <span>{cellValue}</span>
718
+ <span>{formattedCellValue}</span>
737
719
  )}
738
720
  </div>
739
721
  </ContextMenu>
@@ -775,23 +757,29 @@ const QueryBuilderGridResult = observer(
775
757
  rowData={rowData}
776
758
  gridOptions={{
777
759
  suppressScrollOnNewData: true,
778
- getRowId: function (data) {
779
- return data.data.rowNumber as string;
780
- },
760
+ getRowId: (data) => data.data.rowNumber,
761
+ }}
762
+ // NOTE: when column definition changed, we need to force refresh the cell to make sure the cell renderer is updated
763
+ // See https://stackoverflow.com/questions/56341073/how-to-refresh-an-ag-grid-when-a-change-occurs-inside-a-custom-cell-renderer-com
764
+ onRowDataUpdated={(params) => {
765
+ params.api.refreshCells({ force: true });
781
766
  }}
782
767
  suppressFieldDotNotation={true}
783
- columnDefs={executionResult.result.columns.map((colName) => ({
784
- minWidth: 50,
785
- sortable: true,
786
- resizable: true,
787
- field: colName,
788
- flex: 1,
789
- cellRenderer: QueryResultCellRenderer,
790
- cellRendererParams: {
791
- resultState: resultState,
792
- tdsExecutionResult: executionResult,
793
- },
794
- }))}
768
+ columnDefs={executionResult.result.columns.map(
769
+ (colName) =>
770
+ ({
771
+ minWidth: 50,
772
+ sortable: true,
773
+ resizable: true,
774
+ field: colName,
775
+ flex: 1,
776
+ cellRenderer: QueryResultCellRenderer,
777
+ cellRendererParams: {
778
+ resultState: resultState,
779
+ tdsExecutionResult: executionResult,
780
+ },
781
+ }) as DataGridColumnDefinition,
782
+ )}
795
783
  />
796
784
  </div>
797
785
  </div>
@@ -30,7 +30,6 @@ import {
30
30
  PanelDropZone,
31
31
  DragPreviewLayer,
32
32
  useDragPreviewLayer,
33
- OptionsIcon,
34
33
  PlusIcon,
35
34
  PanelContent,
36
35
  TrashIcon,
@@ -41,6 +40,7 @@ import {
41
40
  CustomSelectorInput,
42
41
  PanelEntryDropZonePlaceholder,
43
42
  FunctionIcon,
43
+ CogIcon,
44
44
  } from '@finos/legend-art';
45
45
  import {
46
46
  type QueryBuilderExplorerTreeDragSource,
@@ -952,6 +952,7 @@ export const QueryBuilderTDSPanel = observer(
952
952
  const clearAllProjectionColumns = (): void => {
953
953
  tdsState.checkBeforeClearingColumns(() => {
954
954
  tdsState.removeAllColumns();
955
+ tdsState.resultSetModifierState.reset();
955
956
  });
956
957
  };
957
958
 
@@ -1061,35 +1062,92 @@ export const QueryBuilderTDSPanel = observer(
1061
1062
  return (
1062
1063
  <PanelContent>
1063
1064
  <div className="query-builder__projection__toolbar">
1064
- <button
1065
- className="panel__header__action"
1066
- onClick={openResultSetModifierEditor}
1067
- tabIndex={-1}
1068
- title="Configure result set modifiers..."
1069
- >
1070
- <OptionsIcon className="query-builder__icon query-builder__icon__query-option" />
1071
- </button>
1072
- <button
1073
- className="panel__header__action"
1074
- disabled={isEmpty}
1075
- onClick={clearAllProjectionColumns}
1076
- tabIndex={-1}
1077
- title={
1078
- isEmpty
1079
- ? 'No projection columns to clear'
1080
- : 'Clear all projection columns'
1065
+ <div
1066
+ className="query-builder__projection__result-modifier-prompt"
1067
+ data-testid={
1068
+ QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TDS_RESULT_MODIFIER_PROMPT
1081
1069
  }
1082
1070
  >
1083
- <TrashIcon className="query-builder__icon query-builder__icon__query-option--small" />
1084
- </button>
1085
- <button
1086
- className="panel__header__action"
1087
- onClick={addNewBlankDerivation}
1088
- tabIndex={-1}
1089
- title="Add a new derivation"
1090
- >
1091
- <PlusIcon />
1092
- </button>
1071
+ <div className="query-builder__projection__result-modifier-prompt__header">
1072
+ <button
1073
+ className="query-builder__projection__result-modifier-prompt__header__label"
1074
+ onClick={openResultSetModifierEditor}
1075
+ title="Configure result set modifiers..."
1076
+ >
1077
+ <CogIcon className="query-builder__projection__result-modifier-prompt__header__label__icon" />
1078
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1079
+ Query Options
1080
+ </div>
1081
+ </button>
1082
+ </div>
1083
+ {tdsState.resultSetModifierState.limit && (
1084
+ <div className="query-builder__projection__result-modifier-prompt__group">
1085
+ <div className="query-builder__projection__result-modifier-prompt__group__label">
1086
+ Max Rows
1087
+ </div>
1088
+ <div
1089
+ className="query-builder__projection__result-modifier-prompt__group__content"
1090
+ onClick={openResultSetModifierEditor}
1091
+ >
1092
+ {tdsState.resultSetModifierState.limit}
1093
+ </div>
1094
+ </div>
1095
+ )}
1096
+ {tdsState.resultSetModifierState.distinct && (
1097
+ <div className="query-builder__projection__result-modifier-prompt__group">
1098
+ <div className="query-builder__projection__result-modifier-prompt__group__label">
1099
+ Eliminate Duplicate Rows
1100
+ </div>
1101
+ <div
1102
+ className="query-builder__projection__result-modifier-prompt__group__content"
1103
+ onClick={openResultSetModifierEditor}
1104
+ >
1105
+ Yes
1106
+ </div>
1107
+ </div>
1108
+ )}
1109
+ {tdsState.resultSetModifierState.sortColumns.length > 0 && (
1110
+ <div className="query-builder__projection__result-modifier-prompt__group">
1111
+ <div className="query-builder__projection__result-modifier-prompt__group__label">
1112
+ Sort
1113
+ </div>
1114
+ {tdsState.resultSetModifierState.sortColumns.map(
1115
+ (columnState) => (
1116
+ <div
1117
+ className="query-builder__projection__result-modifier-prompt__group__content"
1118
+ key={columnState.columnState.uuid}
1119
+ onClick={openResultSetModifierEditor}
1120
+ >
1121
+ {`${columnState.columnState.columnName} ${columnState.sortType}`}
1122
+ </div>
1123
+ ),
1124
+ )}
1125
+ </div>
1126
+ )}
1127
+ </div>
1128
+ <div className="query-builder__projection__toolbar__actions">
1129
+ <button
1130
+ className="panel__header__action"
1131
+ disabled={isEmpty}
1132
+ onClick={clearAllProjectionColumns}
1133
+ tabIndex={-1}
1134
+ title={
1135
+ isEmpty
1136
+ ? 'No projection columns to clear'
1137
+ : 'Clear all projection columns'
1138
+ }
1139
+ >
1140
+ <TrashIcon className="query-builder__icon query-builder__icon__query-option--small" />
1141
+ </button>
1142
+ <button
1143
+ className="panel__header__action"
1144
+ onClick={addNewBlankDerivation}
1145
+ tabIndex={-1}
1146
+ title="Add a new derivation"
1147
+ >
1148
+ <PlusIcon />
1149
+ </button>
1150
+ </div>
1093
1151
  </div>
1094
1152
  <div className="query-builder__projection__content">
1095
1153
  <PanelDropZone
@@ -18,3 +18,5 @@ export enum QUERY_BUILDER_CALENDAR_TYPE {
18
18
  NY = 'NY',
19
19
  LDN = 'LDN',
20
20
  }
21
+
22
+ export const DEFAULT_LOCALE = 'en-US';
@@ -98,13 +98,13 @@ export class QueryBuilderResultState {
98
98
  mousedOverCell: observable,
99
99
  isRunningQuery: observable,
100
100
  isSelectingCells: observable,
101
- setIsSelectingCells: action,
102
101
  isQueryUsageViewerOpened: observable,
102
+ setIsSelectingCells: action,
103
103
  setIsRunningQuery: action,
104
104
  setExecutionResult: action,
105
105
  setExecutionDuration: action,
106
106
  setPreviewLimit: action,
107
- addCellData: action,
107
+ addSelectedCell: action,
108
108
  setSelectedCells: action,
109
109
  setMouseOverCell: action,
110
110
  setQueryRunPromise: action,
@@ -124,43 +124,41 @@ export class QueryBuilderResultState {
124
124
  );
125
125
  }
126
126
 
127
- setIsSelectingCells = (val: boolean): void => {
127
+ setIsSelectingCells(val: boolean): void {
128
128
  this.isSelectingCells = val;
129
- };
129
+ }
130
130
 
131
- setIsRunningQuery = (val: boolean): void => {
131
+ setIsRunningQuery(val: boolean): void {
132
132
  this.isRunningQuery = val;
133
- };
133
+ }
134
134
 
135
- setExecutionResult = (val: ExecutionResult | undefined): void => {
135
+ setExecutionResult(val: ExecutionResult | undefined): void {
136
136
  this.executionResult = val;
137
- };
137
+ }
138
138
 
139
- setExecutionDuration = (val: number | undefined): void => {
139
+ setExecutionDuration(val: number | undefined): void {
140
140
  this.executionDuration = val;
141
- };
141
+ }
142
142
 
143
- setPreviewLimit = (val: number): void => {
143
+ setPreviewLimit(val: number): void {
144
144
  this.previewLimit = Math.max(1, val);
145
- };
145
+ }
146
146
 
147
- addCellData = (val: QueryBuilderTDSResultCellData): void => {
147
+ addSelectedCell(val: QueryBuilderTDSResultCellData): void {
148
148
  this.selectedCells.push(val);
149
- };
149
+ }
150
150
 
151
- setSelectedCells = (val: QueryBuilderTDSResultCellData[]): void => {
151
+ setSelectedCells(val: QueryBuilderTDSResultCellData[]): void {
152
152
  this.selectedCells = val;
153
- };
153
+ }
154
154
 
155
- setMouseOverCell = (val: QueryBuilderTDSResultCellData | null): void => {
155
+ setMouseOverCell(val: QueryBuilderTDSResultCellData | null): void {
156
156
  this.mousedOverCell = val;
157
- };
157
+ }
158
158
 
159
- setQueryRunPromise = (
160
- promise: Promise<ExecutionResult> | undefined,
161
- ): void => {
159
+ setQueryRunPromise(promise: Promise<ExecutionResult> | undefined): void {
162
160
  this.queryRunPromise = promise;
163
- };
161
+ }
164
162
 
165
163
  setIsQueryUsageViewerOpened(val: boolean): void {
166
164
  this.isQueryUsageViewerOpened = val;
@@ -82,6 +82,7 @@ export class QueryResultSetModifierState implements Hashable {
82
82
  deleteSortColumn: action,
83
83
  addSortColumn: action,
84
84
  updateSortColumns: action,
85
+ reset: action,
85
86
  hashCode: computed,
86
87
  });
87
88
 
@@ -114,6 +115,12 @@ export class QueryResultSetModifierState implements Hashable {
114
115
  );
115
116
  }
116
117
 
118
+ reset(): void {
119
+ this.sortColumns = [];
120
+ this.distinct = false;
121
+ this.limit = undefined;
122
+ }
123
+
117
124
  get hashCode(): string {
118
125
  return hashArray([
119
126
  QUERY_BUILDER_STATE_HASH_STRUCTURE.RESULT_SET_MODIFIER_STATE,
@@ -62,6 +62,8 @@ export class QueryBuilderBitemporalMilestoningImplementation extends QueryBuilde
62
62
  ),
63
63
  );
64
64
  }
65
+ // Show the parameter panel because we populate paramaters state with milestoning parameters
66
+ this.milestoningState.queryBuilderState.setShowParametersPanel(true);
65
67
  }
66
68
 
67
69
  processGetAllParamaters(parameterValues: ValueSpecification[]): void {
@@ -43,6 +43,8 @@ export class QueryBuilderBusinessTemporalMilestoningImplementation extends Query
43
43
  ),
44
44
  );
45
45
  }
46
+ // Show the parameter panel because we populate paramaters state with milestoning parameters
47
+ this.milestoningState.queryBuilderState.setShowParametersPanel(true);
46
48
  }
47
49
 
48
50
  processGetAllParamaters(parameterValues: ValueSpecification[]): void {
@@ -140,8 +140,6 @@ export class QueryBuilderMilestoningState implements Hashable {
140
140
  this.setProcessingDate(undefined);
141
141
  if (stereotype) {
142
142
  this.initializeQueryMilestoningParameters(stereotype);
143
- // Show the parameter panel because we populate paramaters state with milestoning parameters
144
- this.queryBuilderState.setShowParametersPanel(true);
145
143
  }
146
144
  }
147
145
  }
@@ -42,6 +42,8 @@ export class QueryBuilderProcessingTemporalMilestoningImplementation extends Que
42
42
  ),
43
43
  );
44
44
  }
45
+ // Show the parameter panel because we populate paramaters state with milestoning parameters
46
+ this.milestoningState.queryBuilderState.setShowParametersPanel(true);
45
47
  }
46
48
 
47
49
  processGetAllParamaters(parameterValues: ValueSpecification[]): void {