@finos/legend-query-builder 4.14.70 → 4.14.72

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/lib/components/QueryBuilderConstantExpressionPanel.d.ts.map +1 -1
  2. package/lib/components/QueryBuilderConstantExpressionPanel.js +2 -1
  3. package/lib/components/QueryBuilderConstantExpressionPanel.js.map +1 -1
  4. package/lib/components/QueryLoader.d.ts.map +1 -1
  5. package/lib/components/QueryLoader.js +12 -34
  6. package/lib/components/QueryLoader.js.map +1 -1
  7. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  8. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +10 -3
  9. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  10. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.d.ts.map +1 -1
  11. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js +2 -2
  12. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js.map +1 -1
  13. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  14. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +6 -2
  15. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  16. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  17. package/lib/components/filter/QueryBuilderFilterPanel.js +5 -1
  18. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  19. package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -1
  20. package/lib/components/result/tds/QueryBuilderTDSGridResult.js +5 -16
  21. package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -1
  22. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts +3 -1
  23. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts.map +1 -1
  24. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js +88 -31
  25. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js.map +1 -1
  26. package/lib/index.css +2 -2
  27. package/lib/index.css.map +1 -1
  28. package/lib/package.json +1 -1
  29. package/lib/stores/QueryBuilderConstantsState.d.ts +1 -0
  30. package/lib/stores/QueryBuilderConstantsState.d.ts.map +1 -1
  31. package/lib/stores/QueryBuilderConstantsState.js +6 -1
  32. package/lib/stores/QueryBuilderConstantsState.js.map +1 -1
  33. package/lib/stores/QueryBuilderValueSpecificationHelper.d.ts +1 -1
  34. package/lib/stores/QueryBuilderValueSpecificationHelper.d.ts.map +1 -1
  35. package/lib/stores/QueryBuilderValueSpecificationHelper.js +1 -0
  36. package/lib/stores/QueryBuilderValueSpecificationHelper.js.map +1 -1
  37. package/lib/stores/QueryLoaderState.d.ts +8 -6
  38. package/lib/stores/QueryLoaderState.d.ts.map +1 -1
  39. package/lib/stores/QueryLoaderState.js +30 -7
  40. package/lib/stores/QueryLoaderState.js.map +1 -1
  41. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts +4 -1
  42. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
  43. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +22 -11
  44. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
  45. package/lib/stores/filter/QueryBuilderFilterState.d.ts +1 -1
  46. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  47. package/lib/stores/filter/QueryBuilderFilterState.js +8 -4
  48. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  49. package/package.json +3 -3
  50. package/src/components/QueryBuilderConstantExpressionPanel.tsx +2 -1
  51. package/src/components/QueryLoader.tsx +37 -54
  52. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +24 -2
  53. package/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx +6 -2
  54. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +10 -2
  55. package/src/components/filter/QueryBuilderFilterPanel.tsx +10 -1
  56. package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +8 -16
  57. package/src/components/result/tds/QueryBuilderTDSSimpleGridResult.tsx +96 -34
  58. package/src/stores/QueryBuilderConstantsState.ts +16 -1
  59. package/src/stores/QueryBuilderValueSpecificationHelper.ts +2 -1
  60. package/src/stores/QueryLoaderState.ts +43 -17
  61. package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +39 -10
  62. package/src/stores/filter/QueryBuilderFilterState.ts +11 -3
@@ -746,7 +746,8 @@ export const QueryResultModifierModal = observer(
746
746
  classes={{
747
747
  root: 'editor-modal__root-container',
748
748
  container: 'editor-modal__container',
749
- paper: 'editor-modal__content',
749
+ paper:
750
+ 'editor-modal__content query-builder__projection__modal__content',
750
751
  }}
751
752
  data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL}
752
753
  >
@@ -756,7 +757,10 @@ export const QueryResultModifierModal = observer(
756
757
  }
757
758
  className="editor-modal query-builder__projection__modal"
758
759
  >
759
- <ModalHeader title="Query Options" />
760
+ <ModalHeader
761
+ className="query-builder__projection__modal__header"
762
+ title="Query Options"
763
+ />
760
764
  <ModalBody className="query-builder__projection__modal__body">
761
765
  <div className="query-builder__projection__options">
762
766
  {tdsState.queryBuilderState.milestoningState
@@ -214,7 +214,8 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
214
214
  }) => {
215
215
  const { projectionColumnState } = props;
216
216
  const hasParserError = projectionColumnState.tdsState.hasParserError;
217
- const onEditorBlur = (): void => {
217
+
218
+ const onEditorBlur = useCallback((): void => {
218
219
  flowResult(
219
220
  projectionColumnState.fetchDerivationLambdaReturnType({
220
221
  forceConversionStringToLambda: true,
@@ -224,7 +225,8 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
224
225
  projectionColumnState.tdsState.queryBuilderState.applicationStore
225
226
  .alertUnhandledError,
226
227
  );
227
- };
228
+ }, [projectionColumnState]);
229
+
228
230
  const handleDrop = useCallback(
229
231
  (
230
232
  item: QueryBuilderDerivationProjectionColumnDropTarget,
@@ -256,6 +258,7 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
256
258
  },
257
259
  [projectionColumnState],
258
260
  );
261
+
259
262
  const [, dropConnector] =
260
263
  useDrop<QueryBuilderDerivationProjectionColumnDropTarget>(
261
264
  () => ({
@@ -269,6 +272,11 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
269
272
  [handleDrop],
270
273
  );
271
274
 
275
+ // Calculate derivation return type on mount
276
+ useEffect(() => {
277
+ onEditorBlur();
278
+ }, [onEditorBlur]);
279
+
272
280
  return (
273
281
  <div
274
282
  ref={dropConnector}
@@ -1020,13 +1020,22 @@ const QueryBuilderFilterConditionEditor = observer(
1020
1020
  rightConditionValue instanceof FilterValueSpecConditionValueState &&
1021
1021
  rightConditionValue.value
1022
1022
  ) {
1023
+ const isInvalidVariable =
1024
+ rightConditionValue.value instanceof VariableExpression &&
1025
+ node.condition.filterState.isInvalidValueSpecFilterValue(node);
1023
1026
  return (
1024
1027
  <div
1025
1028
  ref={dropConnector}
1026
1029
  data-testid={
1027
1030
  QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_CONDITION_NODE_VALUE
1028
1031
  }
1029
- className="query-builder-filter-tree__condition-node__value"
1032
+ className={clsx(
1033
+ 'query-builder-filter-tree__condition-node__value',
1034
+ {
1035
+ 'query-builder-filter-tree__condition-node__value--error':
1036
+ isInvalidVariable,
1037
+ },
1038
+ )}
1030
1039
  >
1031
1040
  <PanelEntryDropZonePlaceholder
1032
1041
  isDragOver={isFilterValueDragOver}
@@ -61,7 +61,10 @@ import {
61
61
  Dialog,
62
62
  CustomSelectorInput,
63
63
  } from '@finos/legend-art';
64
- import { getFloatGridColumnCustomHeader } from './QueryBuilderTDSSimpleGridResult.js';
64
+ import {
65
+ getTDSColumnCustomizations,
66
+ MAXIMUM_FRACTION_DIGITS,
67
+ } from './QueryBuilderTDSSimpleGridResult.js';
65
68
 
66
69
  export const enum QueryBuilderDataGridCustomAggregationFunction {
67
70
  wavg = 'wavg',
@@ -88,20 +91,13 @@ const getAggregationTDSColumnCustomizations = (
88
91
  filter: 'agDateColumnFilter',
89
92
  allowedAggFuncs: ['count'],
90
93
  };
94
+ case PRIMITIVE_TYPE.DECIMAL:
91
95
  case PRIMITIVE_TYPE.NUMBER:
92
96
  case PRIMITIVE_TYPE.INTEGER:
93
- return {
94
- filter: 'agNumberColumnFilter',
95
- allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
96
- };
97
- case PRIMITIVE_TYPE.DECIMAL:
98
97
  case PRIMITIVE_TYPE.FLOAT:
99
98
  return {
100
99
  filter: 'agNumberColumnFilter',
101
100
  allowedAggFuncs: ['count', 'sum', 'max', 'min', 'avg', 'wavg'],
102
- headerComponentParams: {
103
- template: getFloatGridColumnCustomHeader(columnName),
104
- },
105
101
  };
106
102
  default:
107
103
  return {
@@ -117,7 +113,7 @@ const QueryResultCellRenderer = observer(
117
113
  const formattedCellValue = (): QueryBuilderTDSResultCellDataType => {
118
114
  if (isNumber(cellValue)) {
119
115
  return Intl.NumberFormat(DEFAULT_LOCALE, {
120
- maximumFractionDigits: 4,
116
+ maximumFractionDigits: MAXIMUM_FRACTION_DIGITS,
121
117
  }).format(Number(cellValue));
122
118
  } else if (isBoolean(cellValue)) {
123
119
  return String(cellValue);
@@ -181,6 +177,7 @@ const getLocalColDefs = (
181
177
  tdsExecutionResult: executionResult,
182
178
  },
183
179
  ...getAggregationTDSColumnCustomizations(executionResult, colName),
180
+ ...getTDSColumnCustomizations(executionResult, colName),
184
181
  } as DataGridColumnDefinition;
185
182
  const persistedColumn = resultState.gridConfig?.columns.find(
186
183
  (c) => c.colId === colName,
@@ -216,15 +213,9 @@ const getFilterTDSColumnCustomizations = (
216
213
  case PRIMITIVE_TYPE.DECIMAL:
217
214
  case PRIMITIVE_TYPE.INTEGER:
218
215
  case PRIMITIVE_TYPE.NUMBER:
219
- return {
220
- filter: 'agNumberColumnFilter',
221
- };
222
216
  case PRIMITIVE_TYPE.FLOAT:
223
217
  return {
224
218
  filter: 'agNumberColumnFilter',
225
- headerComponentParams: {
226
- template: getFloatGridColumnCustomHeader(columnName),
227
- },
228
219
  };
229
220
  default:
230
221
  // we default all other columns to use filter true which defaults to set filters
@@ -255,6 +246,7 @@ const getColDefs = (
255
246
  tdsExecutionResult: executionResult,
256
247
  },
257
248
  ...getFilterTDSColumnCustomizations(executionResult, colName),
249
+ ...getTDSColumnCustomizations(executionResult, colName),
258
250
  }) as DataGridColumnDefinition,
259
251
  );
260
252
 
@@ -48,45 +48,107 @@ import type {
48
48
  } from '../../../stores/QueryBuilderResultState.js';
49
49
  import { QUERY_BUILDER_TEST_ID } from '../../../__lib__/QueryBuilderTesting.js';
50
50
 
51
- export const getFloatGridColumnCustomHeader = (
52
- columnName: string,
53
- ): string => ` <div data-testid="query__builder__result__grid__custom-header" class="query-builder__result__values__table__custom-header">
54
- <div>${columnName}</div>
55
- <div
56
- class="query-builder__result__stale-status__icon"
57
- title="some values have been rounded using en-us format in this preview grid (defaults to max 4 decimal places)"
58
- >
59
- <svg
60
- stroke="currentColor"
61
- fill="currentColor"
62
- stroke-width="0"
63
- viewBox="0 0 576 512"
64
- height="1em"
65
- width="1em"
66
- xmlns="http://www.w3.org/2000/svg"
67
- >
68
- <path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path>
69
- </svg>
70
- </div>
71
- </div>`;
51
+ export const MAXIMUM_FRACTION_DIGITS = 4;
52
+
53
+ export const getFloatGridColumnCustomHeader = (): string =>
54
+ `<div class="ag-cell-label-container" role="presentation">
55
+ <span
56
+ data-ref="eMenu"
57
+ class="ag-header-icon ag-header-cell-menu-button"
58
+ ></span>
59
+ <span
60
+ data-ref="eFilterButton"
61
+ class="ag-header-icon ag-header-cell-filter-button"
62
+ ></span>
63
+ <div data-ref="eLabel" class="ag-header-cell-label" role="presentation">
64
+ <span
65
+ data-ref="eSortOrder"
66
+ class="ag-header-icon ag-sort-order ag-hidden"
67
+ ></span>
68
+ <span
69
+ data-ref="eSortAsc"
70
+ class="ag-header-icon ag-sort-ascending-icon ag-hidden"
71
+ ></span>
72
+ <span
73
+ data-ref="eSortDesc"
74
+ class="ag-header-icon ag-sort-descending-icon ag-hidden"
75
+ ></span>
76
+ <span
77
+ data-ref="eSortMixed"
78
+ class="ag-header-icon ag-sort-mixed-icon ag-hidden"
79
+ ></span>
80
+ <span
81
+ data-ref="eSortNone"
82
+ class="ag-header-icon ag-sort-none-icon ag-hidden"
83
+ ></span>
84
+ <span
85
+ data-ref="eText"
86
+ class="ag-header-cell-text"
87
+ role="columnheader"
88
+ ></span>
89
+ <span data-ref="eFilter" class="ag-header-icon ag-filter-icon"></span>
90
+ </div>
91
+ <div
92
+ data-testid="query__builder__result__grid__custom-header"
93
+ class="query-builder__result__values__table__custom-header"
94
+ >
95
+ <div
96
+ class="query-builder__result__values__table__custom-header__icon"
97
+ title="some values have been rounded using en-us format in this preview grid (defaults to max 4 decimal places)"
98
+ >
99
+ <svg
100
+ stroke="currentColor"
101
+ fill="currentColor"
102
+ stroke-width="0"
103
+ viewBox="0 0 576 512"
104
+ height="1em"
105
+ width="1em"
106
+ xmlns="http://www.w3.org/2000/svg"
107
+ >
108
+ <path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path>
109
+ </svg>
110
+ </div>
111
+ </div>
112
+ </div>`;
72
113
 
73
- const getTDSColumnCustomizations = (
114
+ export const getTDSColumnCustomizations = (
74
115
  result: TDSExecutionResult,
75
116
  columnName: string,
76
117
  ): object => {
77
- const columnType = result.builder.columns.find(
118
+ const index = result.builder.columns.findIndex(
78
119
  (col) => col.name === columnName,
79
- )?.type;
80
- switch (columnType) {
81
- case PRIMITIVE_TYPE.FLOAT:
82
- return {
83
- headerComponentParams: {
84
- template: getFloatGridColumnCustomHeader(columnName),
85
- },
86
- };
87
- default:
88
- return {};
120
+ );
121
+ if (index >= 0) {
122
+ const columnType = result.builder.columns[index]?.type;
123
+ const colValues = result.result.rows.map((r) => r.values[index]);
124
+ const isTruncated = (
125
+ vals: (string | number | boolean | null | undefined)[],
126
+ ): boolean =>
127
+ Boolean(
128
+ vals.some((val) => {
129
+ if (val) {
130
+ const decimalPart = val.toString().split('.')[1];
131
+ return decimalPart && decimalPart.length > MAXIMUM_FRACTION_DIGITS;
132
+ }
133
+ return false;
134
+ }),
135
+ );
136
+ switch (columnType) {
137
+ case PRIMITIVE_TYPE.NUMBER:
138
+ case PRIMITIVE_TYPE.DECIMAL:
139
+ case PRIMITIVE_TYPE.FLOAT:
140
+ return isTruncated(colValues)
141
+ ? {
142
+ headerComponentParams: {
143
+ template: getFloatGridColumnCustomHeader(),
144
+ },
145
+ }
146
+ : {};
147
+ default:
148
+ return {};
149
+ }
89
150
  }
151
+ return {};
90
152
  };
91
153
 
92
154
  const QueryResultCellRenderer = observer(
@@ -104,7 +166,7 @@ const QueryResultCellRenderer = observer(
104
166
  const formattedCellValue = (): QueryBuilderTDSResultCellDataType => {
105
167
  if (isNumber(cellValue)) {
106
168
  return Intl.NumberFormat(DEFAULT_LOCALE, {
107
- maximumFractionDigits: 4,
169
+ maximumFractionDigits: MAXIMUM_FRACTION_DIGITS,
108
170
  }).format(Number(cellValue));
109
171
  } else if (isBoolean(cellValue)) {
110
172
  return String(cellValue);
@@ -288,6 +288,7 @@ export class QueryBuilderCalculatedConstantExpressionState
288
288
  variable: observable,
289
289
  lambdaState: observable,
290
290
  value: observable,
291
+ setLambdaState: action,
291
292
  setValue: action,
292
293
  });
293
294
  this.value = value;
@@ -298,6 +299,10 @@ export class QueryBuilderCalculatedConstantExpressionState
298
299
  );
299
300
  }
300
301
 
302
+ setLambdaState(val: QueryBuilderConstantLambdaEditorState): void {
303
+ this.lambdaState = val;
304
+ }
305
+
301
306
  setValue(val: PlainObject): void {
302
307
  this.value = val;
303
308
  }
@@ -393,8 +398,18 @@ export class QueryBuilderConstantsState implements Hashable {
393
398
  export const cloneQueryBuilderConstantLambdaEditorState = (
394
399
  state: QueryBuilderConstantLambdaEditorState,
395
400
  ): QueryBuilderConstantLambdaEditorState => {
401
+ const clonedCalculatedState =
402
+ new QueryBuilderCalculatedConstantExpressionState(
403
+ state.calculatedState.queryBuilderState,
404
+ new VariableExpression(
405
+ state.calculatedState.variable.name,
406
+ state.calculatedState.variable.multiplicity,
407
+ state.calculatedState.variable.genericType,
408
+ ),
409
+ deepClone(state.calculatedState.value),
410
+ );
396
411
  const clonedState = new QueryBuilderConstantLambdaEditorState(
397
- deepClone(state.calculatedState),
412
+ clonedCalculatedState,
398
413
  );
399
414
  clonedState.lambdaString = state.lambdaString;
400
415
  clonedState.parserError = deepClone(state.parserError);
@@ -213,7 +213,7 @@ export const isPropertyExpressionChainOptional = (
213
213
 
214
214
  export const isTypeCompatibleForAssignment = (
215
215
  type: Type | undefined,
216
- assignmentType: Type,
216
+ assignmentType: Type | undefined,
217
217
  ): boolean => {
218
218
  const NUMERIC_PRIMITIVE_TYPES = [
219
219
  PRIMITIVE_TYPE.NUMBER,
@@ -231,6 +231,7 @@ export const isTypeCompatibleForAssignment = (
231
231
  // When changing the return type for LHS, the RHS value should be adjusted accordingly.
232
232
  return (
233
233
  type !== undefined &&
234
+ assignmentType !== undefined &&
234
235
  // Numeric value is handled loosely because of autoboxing
235
236
  // e.g. LHS (integer) = RHS (float) is acceptable
236
237
  ((NUMERIC_PRIMITIVE_TYPES.includes(type.path) &&
@@ -19,17 +19,18 @@ import {
19
19
  type GenericLegendApplicationStore,
20
20
  } from '@finos/legend-application';
21
21
  import {
22
- QuerySearchSpecification,
23
- GRAPH_MANAGER_EVENT,
24
22
  type QueryInfo,
25
23
  type LightQuery,
26
24
  type BasicGraphManagerState,
27
25
  type Query,
28
26
  type RawLambda,
27
+ QuerySearchSpecification,
28
+ GRAPH_MANAGER_EVENT,
29
+ QuerySearchSortBy,
29
30
  } from '@finos/legend-graph';
30
31
  import {
31
- ActionState,
32
32
  type GeneratorFn,
33
+ ActionState,
33
34
  assertErrorThrown,
34
35
  guaranteeNonNullable,
35
36
  LogEvent,
@@ -51,7 +52,7 @@ export enum SORT_BY_OPTIONS {
51
52
  SORT_BY_UPDATE = 'Last Updated',
52
53
  }
53
54
 
54
- export type SortByOption = { label: string; value: string };
55
+ export type SortByOption = { label: SORT_BY_OPTIONS; value: SORT_BY_OPTIONS };
55
56
 
56
57
  export class QueryLoaderState {
57
58
  readonly applicationStore: GenericLegendApplicationStore;
@@ -92,7 +93,7 @@ export class QueryLoaderState {
92
93
  showingDefaultQueries = true;
93
94
  showPreviewViewer = false;
94
95
  queryPreviewContent?: QueryInfo | { name: string; content: string };
95
- sortBy = '';
96
+ sortBy = SORT_BY_OPTIONS.SORT_BY_VIEW;
96
97
 
97
98
  constructor(
98
99
  applicationStore: GenericLegendApplicationStore,
@@ -158,10 +159,23 @@ export class QueryLoaderState {
158
159
  this.isCuratedTemplateToggled = val;
159
160
  }
160
161
 
161
- setSortBy(val: string): void {
162
+ setSortBy(val: SORT_BY_OPTIONS): void {
162
163
  this.sortBy = val;
163
164
  }
164
165
 
166
+ getQuerySearchSortBy(sortByValue: string): QuerySearchSortBy | undefined {
167
+ switch (sortByValue) {
168
+ case SORT_BY_OPTIONS.SORT_BY_CREATE:
169
+ return QuerySearchSortBy.SORT_BY_CREATE;
170
+ case SORT_BY_OPTIONS.SORT_BY_UPDATE:
171
+ return QuerySearchSortBy.SORT_BY_UPDATE;
172
+ case SORT_BY_OPTIONS.SORT_BY_VIEW:
173
+ return QuerySearchSortBy.SORT_BY_VIEW;
174
+ default:
175
+ return undefined;
176
+ }
177
+ }
178
+
165
179
  setSearchText(val: string): void {
166
180
  this.searchText = val;
167
181
  }
@@ -171,7 +185,16 @@ export class QueryLoaderState {
171
185
  }
172
186
 
173
187
  setQueries(val: LightQuery[]): void {
174
- this.queries = val.sort((a, b) => a.name.localeCompare(b.name));
188
+ this.queries = val;
189
+ }
190
+
191
+ // search query using search specification
192
+ canPerformAdvancedSearch(searchText: string): boolean {
193
+ return !(
194
+ searchText.length < DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH &&
195
+ !this.showCurrentUserQueriesOnly &&
196
+ Array.from(this.extraFilters.values()).every((value) => value === false)
197
+ );
175
198
  }
176
199
 
177
200
  setShowPreviewViewer(val: boolean): void {
@@ -226,11 +249,7 @@ export class QueryLoaderState {
226
249
  }
227
250
 
228
251
  *searchQueries(searchText: string): GeneratorFn<void> {
229
- if (
230
- searchText.length < DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH &&
231
- !this.showCurrentUserQueriesOnly &&
232
- Array.from(this.extraFilters.values()).every((value) => value === false)
233
- ) {
252
+ if (!this.canPerformAdvancedSearch(searchText)) {
234
253
  // if no search text is specified, use fetch the default queries
235
254
  if (!searchText) {
236
255
  this.showingDefaultQueries = true;
@@ -268,6 +287,10 @@ export class QueryLoaderState {
268
287
  searchSpecification.limit = QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT + 1;
269
288
  searchSpecification.showCurrentUserQueriesOnly =
270
289
  this.showCurrentUserQueriesOnly;
290
+ const querySearchSortBy = this.getQuerySearchSortBy(this.sortBy);
291
+ if (querySearchSortBy) {
292
+ searchSpecification.sortByOption = querySearchSortBy;
293
+ }
271
294
  if (this.queryBuilderState) {
272
295
  Array.from(this.extraFilters.entries()).forEach(([key, value]) => {
273
296
  if (value) {
@@ -288,11 +311,14 @@ export class QueryLoaderState {
288
311
  searchSpecification =
289
312
  this.decorateSearchSpecification?.(searchSpecification) ??
290
313
  searchSpecification;
291
- this.queries = (
292
- (yield this.graphManagerState.graphManager.searchQueries(
293
- searchSpecification,
294
- )) as LightQuery[]
295
- ).sort((a, b) => a.name.localeCompare(b.name));
314
+ this.queries = (yield this.graphManagerState.graphManager.searchQueries(
315
+ searchSpecification,
316
+ )) as LightQuery[];
317
+ if (!querySearchSortBy) {
318
+ this.queries = this.queries.sort((a, b) =>
319
+ a.name.localeCompare(b.name),
320
+ );
321
+ }
296
322
  this.searchQueriesState.pass();
297
323
  } catch (error) {
298
324
  assertErrorThrown(error);
@@ -20,12 +20,12 @@ import {
20
20
  type Type,
21
21
  type ValueSpecification,
22
22
  type ExecutionResult,
23
- type VariableExpression,
24
23
  type SimpleFunctionExpression,
25
24
  observe_ValueSpecification,
26
25
  PrimitiveType,
27
26
  CollectionInstanceValue,
28
27
  InstanceValue,
28
+ VariableExpression,
29
29
  } from '@finos/legend-graph';
30
30
  import {
31
31
  type GeneratorFn,
@@ -74,11 +74,13 @@ import type { QueryBuilderTDSColumnState } from '../QueryBuilderTDSColumnState.j
74
74
  import {
75
75
  getCollectionValueSpecificationType,
76
76
  getNonCollectionValueSpecificationType,
77
+ isTypeCompatibleForAssignment,
77
78
  isValidInstanceValue,
78
79
  isValueExpressionReferencedInValue,
79
80
  } from '../../../QueryBuilderValueSpecificationHelper.js';
80
81
  import { buildtdsPropertyExpressionFromColState } from './operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.js';
81
82
  import { TDS_COLUMN_GETTER } from '../../../../graph/QueryBuilderMetaModelConst.js';
83
+ import type { QueryBuilderFilterTreeNodeData } from '../../../filter/QueryBuilderFilterState.js';
82
84
 
83
85
  export enum QUERY_BUILDER_POST_FILTER_DND_TYPE {
84
86
  GROUP_CONDITION = 'QUERY_BUILDER_POST_FILTER_DND_TYPE.GROUP_CONDITION',
@@ -1011,15 +1013,45 @@ export class QueryBuilderPostFilterState
1011
1013
  );
1012
1014
  }
1013
1015
 
1016
+ isInvalidValueSpecPostFilterValue(
1017
+ node: QueryBuilderPostFilterTreeNodeData,
1018
+ ): boolean {
1019
+ return (
1020
+ node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1021
+ node.condition.rightConditionValue instanceof
1022
+ PostFilterValueSpecConditionValueState &&
1023
+ ((node.condition.rightConditionValue.value instanceof InstanceValue &&
1024
+ !isValidInstanceValue(node.condition.rightConditionValue.value)) ||
1025
+ (node.condition.rightConditionValue.value instanceof
1026
+ VariableExpression &&
1027
+ !isTypeCompatibleForAssignment(
1028
+ node.condition.leftConditionValue.getColumnType(),
1029
+ node.condition.rightConditionValue.type,
1030
+ )))
1031
+ );
1032
+ }
1033
+
1034
+ isInvalidTDSColumnPostFilterValue(
1035
+ node: QueryBuilderFilterTreeNodeData,
1036
+ ): boolean {
1037
+ return (
1038
+ node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1039
+ node.condition.rightConditionValue instanceof
1040
+ PostFilterTDSColumnValueConditionValueState &&
1041
+ !isTypeCompatibleForAssignment(
1042
+ node.condition.leftConditionValue.getColumnType(),
1043
+ node.condition.rightConditionValue.type,
1044
+ )
1045
+ );
1046
+ }
1047
+
1014
1048
  get allValidationIssues(): string[] {
1015
1049
  const validationIssues: string[] = [];
1016
1050
  Array.from(this.nodes.values()).forEach((node) => {
1017
1051
  if (node instanceof QueryBuilderPostFilterTreeConditionNodeData) {
1018
1052
  if (
1019
- node.condition.rightConditionValue instanceof
1020
- PostFilterValueSpecConditionValueState &&
1021
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1022
- !isValidInstanceValue(node.condition.rightConditionValue.value)
1053
+ this.isInvalidValueSpecPostFilterValue(node) ||
1054
+ this.isInvalidTDSColumnPostFilterValue(node)
1023
1055
  ) {
1024
1056
  validationIssues.push(
1025
1057
  `Filter value for ${node.condition.leftConditionValue.columnName} is missing or invalid`,
@@ -1042,11 +1074,8 @@ export class QueryBuilderPostFilterState
1042
1074
  get hasInvalidFilterValues(): boolean {
1043
1075
  return Array.from(this.nodes.values()).some(
1044
1076
  (node) =>
1045
- node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1046
- node.condition.rightConditionValue instanceof
1047
- PostFilterValueSpecConditionValueState &&
1048
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1049
- !isValidInstanceValue(node.condition.rightConditionValue.value),
1077
+ this.isInvalidValueSpecPostFilterValue(node) ||
1078
+ this.isInvalidTDSColumnPostFilterValue(node),
1050
1079
  );
1051
1080
  }
1052
1081
 
@@ -40,12 +40,12 @@ import {
40
40
  type ExecutionResult,
41
41
  AbstractPropertyExpression,
42
42
  type ValueSpecification,
43
- type VariableExpression,
44
43
  type Type,
45
44
  observe_ValueSpecification,
46
45
  CollectionInstanceValue,
47
46
  InstanceValue,
48
47
  SimpleFunctionExpression,
48
+ VariableExpression,
49
49
  matchFunctionName,
50
50
  } from '@finos/legend-graph';
51
51
  import { DEFAULT_LAMBDA_VARIABLE_NAME } from '../QueryBuilderConfig.js';
@@ -61,6 +61,7 @@ import { QUERY_BUILDER_STATE_HASH_STRUCTURE } from '../QueryBuilderStateHashUtil
61
61
  import {
62
62
  getCollectionValueSpecificationType,
63
63
  getNonCollectionValueSpecificationType,
64
+ isTypeCompatibleForAssignment,
64
65
  isValidInstanceValue,
65
66
  isValueExpressionReferencedInValue,
66
67
  } from '../QueryBuilderValueSpecificationHelper.js';
@@ -1185,8 +1186,15 @@ export class QueryBuilderFilterState
1185
1186
  node instanceof QueryBuilderFilterTreeConditionNodeData &&
1186
1187
  node.condition.rightConditionValue instanceof
1187
1188
  FilterValueSpecConditionValueState &&
1188
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1189
- !isValidInstanceValue(node.condition.rightConditionValue.value)
1189
+ ((node.condition.rightConditionValue.value instanceof InstanceValue &&
1190
+ !isValidInstanceValue(node.condition.rightConditionValue.value)) ||
1191
+ (node.condition.rightConditionValue.value instanceof
1192
+ VariableExpression &&
1193
+ !isTypeCompatibleForAssignment(
1194
+ node.condition.propertyExpressionState.propertyExpression.func.value
1195
+ .genericType.value.rawType,
1196
+ node.condition.rightConditionValue.value.genericType?.value.rawType,
1197
+ )))
1190
1198
  );
1191
1199
  }
1192
1200