@finos/legend-application-query 5.0.1 → 5.2.1

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 (210) hide show
  1. package/lib/application/LegendQueryApplicationConfig.d.ts +17 -1
  2. package/lib/application/LegendQueryApplicationConfig.d.ts.map +1 -1
  3. package/lib/application/LegendQueryApplicationConfig.js +23 -1
  4. package/lib/application/LegendQueryApplicationConfig.js.map +1 -1
  5. package/lib/components/QueryBuilder.d.ts.map +1 -1
  6. package/lib/components/QueryBuilder.js +3 -1
  7. package/lib/components/QueryBuilder.js.map +1 -1
  8. package/lib/components/QueryBuilderExplorerPanel.d.ts.map +1 -1
  9. package/lib/components/QueryBuilderExplorerPanel.js +10 -35
  10. package/lib/components/QueryBuilderExplorerPanel.js.map +1 -1
  11. package/lib/components/QueryBuilderFetchStructurePanel.d.ts.map +1 -1
  12. package/lib/components/QueryBuilderFetchStructurePanel.js +78 -35
  13. package/lib/components/QueryBuilderFetchStructurePanel.js.map +1 -1
  14. package/lib/components/QueryBuilderFilterPanel.d.ts.map +1 -1
  15. package/lib/components/QueryBuilderFilterPanel.js +80 -66
  16. package/lib/components/QueryBuilderFilterPanel.js.map +1 -1
  17. package/lib/components/QueryBuilderFunctionsExplorerPanel.d.ts.map +1 -1
  18. package/lib/components/QueryBuilderFunctionsExplorerPanel.js +9 -39
  19. package/lib/components/QueryBuilderFunctionsExplorerPanel.js.map +1 -1
  20. package/lib/components/QueryBuilderGraphFetchTreePanel.d.ts.map +1 -1
  21. package/lib/components/QueryBuilderGraphFetchTreePanel.js +5 -5
  22. package/lib/components/QueryBuilderGraphFetchTreePanel.js.map +1 -1
  23. package/lib/components/QueryBuilderLambdaEditor.d.ts +1 -0
  24. package/lib/components/QueryBuilderLambdaEditor.d.ts.map +1 -1
  25. package/lib/components/QueryBuilderLambdaEditor.js +2 -2
  26. package/lib/components/QueryBuilderLambdaEditor.js.map +1 -1
  27. package/lib/components/QueryBuilderMilestoneEditor.js +5 -5
  28. package/lib/components/QueryBuilderMilestoneEditor.js.map +1 -1
  29. package/lib/components/QueryBuilderPanelIssueCountBadge.d.ts +20 -0
  30. package/lib/components/QueryBuilderPanelIssueCountBadge.d.ts.map +1 -0
  31. package/lib/components/QueryBuilderPanelIssueCountBadge.js +28 -0
  32. package/lib/components/QueryBuilderPanelIssueCountBadge.js.map +1 -0
  33. package/lib/components/QueryBuilderParameterPanel.d.ts.map +1 -1
  34. package/lib/components/QueryBuilderParameterPanel.js +13 -33
  35. package/lib/components/QueryBuilderParameterPanel.js.map +1 -1
  36. package/lib/components/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  37. package/lib/components/QueryBuilderPostFilterPanel.js +59 -62
  38. package/lib/components/QueryBuilderPostFilterPanel.js.map +1 -1
  39. package/lib/components/QueryBuilderProjectionPanel.d.ts.map +1 -1
  40. package/lib/components/QueryBuilderProjectionPanel.js +47 -63
  41. package/lib/components/QueryBuilderProjectionPanel.js.map +1 -1
  42. package/lib/components/QueryBuilderPropertyExpressionEditor.d.ts.map +1 -1
  43. package/lib/components/QueryBuilderPropertyExpressionEditor.js +11 -11
  44. package/lib/components/QueryBuilderPropertyExpressionEditor.js.map +1 -1
  45. package/lib/components/QueryBuilderPropertySearchPanel.js +5 -7
  46. package/lib/components/QueryBuilderPropertySearchPanel.js.map +1 -1
  47. package/lib/components/QueryBuilderResultModifierPanel.d.ts.map +1 -1
  48. package/lib/components/QueryBuilderResultModifierPanel.js +3 -1
  49. package/lib/components/QueryBuilderResultModifierPanel.js.map +1 -1
  50. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  51. package/lib/components/QueryBuilderResultPanel.js +37 -23
  52. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  53. package/lib/components/QueryBuilderSetupPanel.d.ts.map +1 -1
  54. package/lib/components/QueryBuilderSetupPanel.js +10 -9
  55. package/lib/components/QueryBuilderSetupPanel.js.map +1 -1
  56. package/lib/components/QueryBuilderUnsupportedQueryEditor.d.ts.map +1 -1
  57. package/lib/components/QueryBuilderUnsupportedQueryEditor.js +4 -2
  58. package/lib/components/QueryBuilderUnsupportedQueryEditor.js.map +1 -1
  59. package/lib/components/QueryEditor.d.ts.map +1 -1
  60. package/lib/components/QueryEditor.js +16 -4
  61. package/lib/components/QueryEditor.js.map +1 -1
  62. package/lib/index.css +2 -2
  63. package/lib/index.css.map +1 -1
  64. package/lib/package.json +10 -9
  65. package/lib/stores/QueryBuilderExplorerState.d.ts +1 -1
  66. package/lib/stores/QueryBuilderExplorerState.d.ts.map +1 -1
  67. package/lib/stores/QueryBuilderExplorerState.js +18 -3
  68. package/lib/stores/QueryBuilderExplorerState.js.map +1 -1
  69. package/lib/stores/QueryBuilderFetchStructureState.d.ts +8 -1
  70. package/lib/stores/QueryBuilderFetchStructureState.d.ts.map +1 -1
  71. package/lib/stores/QueryBuilderFetchStructureState.js +10 -2
  72. package/lib/stores/QueryBuilderFetchStructureState.js.map +1 -1
  73. package/lib/stores/QueryBuilderFilterState.d.ts +10 -5
  74. package/lib/stores/QueryBuilderFilterState.d.ts.map +1 -1
  75. package/lib/stores/QueryBuilderFilterState.js +34 -8
  76. package/lib/stores/QueryBuilderFilterState.js.map +1 -1
  77. package/lib/stores/QueryBuilderGraphFetchTreeState.d.ts.map +1 -1
  78. package/lib/stores/QueryBuilderGraphFetchTreeState.js +6 -3
  79. package/lib/stores/QueryBuilderGraphFetchTreeState.js.map +1 -1
  80. package/lib/stores/QueryBuilderLambdaProcessor.d.ts.map +1 -1
  81. package/lib/stores/QueryBuilderLambdaProcessor.js +2 -0
  82. package/lib/stores/QueryBuilderLambdaProcessor.js.map +1 -1
  83. package/lib/stores/QueryBuilderOperatorLoader.d.ts +47 -0
  84. package/lib/stores/QueryBuilderOperatorLoader.d.ts.map +1 -0
  85. package/lib/stores/QueryBuilderOperatorLoader.js +94 -0
  86. package/lib/stores/QueryBuilderOperatorLoader.js.map +1 -0
  87. package/lib/stores/QueryBuilderOperatorsHelper.d.ts +1 -0
  88. package/lib/stores/QueryBuilderOperatorsHelper.d.ts.map +1 -1
  89. package/lib/stores/QueryBuilderOperatorsHelper.js +28 -1
  90. package/lib/stores/QueryBuilderOperatorsHelper.js.map +1 -1
  91. package/lib/stores/QueryBuilderPostFilterState.d.ts +9 -6
  92. package/lib/stores/QueryBuilderPostFilterState.d.ts.map +1 -1
  93. package/lib/stores/QueryBuilderPostFilterState.js +31 -7
  94. package/lib/stores/QueryBuilderPostFilterState.js.map +1 -1
  95. package/lib/stores/QueryBuilderPreviewDataHelper.d.ts +4 -3
  96. package/lib/stores/QueryBuilderPreviewDataHelper.d.ts.map +1 -1
  97. package/lib/stores/QueryBuilderPreviewDataHelper.js +77 -97
  98. package/lib/stores/QueryBuilderPreviewDataHelper.js.map +1 -1
  99. package/lib/stores/QueryBuilderProjectionState.d.ts +4 -7
  100. package/lib/stores/QueryBuilderProjectionState.d.ts.map +1 -1
  101. package/lib/stores/QueryBuilderProjectionState.js +23 -39
  102. package/lib/stores/QueryBuilderProjectionState.js.map +1 -1
  103. package/lib/stores/QueryBuilderPropertySearchPanelState.js +1 -1
  104. package/lib/stores/QueryBuilderPropertySearchPanelState.js.map +1 -1
  105. package/lib/stores/QueryBuilderResultState.d.ts +5 -2
  106. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  107. package/lib/stores/QueryBuilderResultState.js +19 -7
  108. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  109. package/lib/stores/QueryBuilderSetupState.js +1 -1
  110. package/lib/stores/QueryBuilderSetupState.js.map +1 -1
  111. package/lib/stores/QueryBuilderState.d.ts +7 -0
  112. package/lib/stores/QueryBuilderState.d.ts.map +1 -1
  113. package/lib/stores/QueryBuilderState.js +18 -58
  114. package/lib/stores/QueryBuilderState.js.map +1 -1
  115. package/lib/stores/QueryBuilderTestUtils.d.ts +24 -0
  116. package/lib/stores/QueryBuilderTestUtils.d.ts.map +1 -0
  117. package/lib/stores/QueryBuilderTestUtils.js +49 -0
  118. package/lib/stores/QueryBuilderTestUtils.js.map +1 -0
  119. package/lib/stores/QueryBuilderTypeaheadHelper.d.ts +24 -0
  120. package/lib/stores/QueryBuilderTypeaheadHelper.d.ts.map +1 -0
  121. package/lib/stores/QueryBuilderTypeaheadHelper.js +89 -0
  122. package/lib/stores/QueryBuilderTypeaheadHelper.js.map +1 -0
  123. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.d.ts.map +1 -1
  124. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.js +7 -7
  125. package/lib/stores/QueryBuilderValueSpecificationBuilderHelper.js.map +1 -1
  126. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  127. package/lib/stores/QueryEditorStore.js +14 -3
  128. package/lib/stores/QueryEditorStore.js.map +1 -1
  129. package/lib/stores/QueryFunctionsExplorerState.d.ts +2 -6
  130. package/lib/stores/QueryFunctionsExplorerState.d.ts.map +1 -1
  131. package/lib/stores/QueryFunctionsExplorerState.js +2 -11
  132. package/lib/stores/QueryFunctionsExplorerState.js.map +1 -1
  133. package/lib/stores/QueryParametersState.d.ts +1 -3
  134. package/lib/stores/QueryParametersState.d.ts.map +1 -1
  135. package/lib/stores/QueryParametersState.js +1 -4
  136. package/lib/stores/QueryParametersState.js.map +1 -1
  137. package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.d.ts.map +1 -1
  138. package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.js +9 -32
  139. package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.js.map +1 -1
  140. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.d.ts.map +1 -1
  141. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.js +9 -32
  142. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.js.map +1 -1
  143. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts.map +1 -1
  144. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.js +9 -32
  145. package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.js.map +1 -1
  146. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.d.ts.map +1 -1
  147. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.js +9 -33
  148. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.js.map +1 -1
  149. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.d.ts.map +1 -1
  150. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.js +9 -32
  151. package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.js.map +1 -1
  152. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.d.ts.map +1 -1
  153. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.js +7 -30
  154. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.js.map +1 -1
  155. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.d.ts.map +1 -1
  156. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.js +8 -31
  157. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.js.map +1 -1
  158. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.d.ts.map +1 -1
  159. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.js +8 -31
  160. package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.js.map +1 -1
  161. package/package.json +17 -16
  162. package/src/application/LegendQueryApplicationConfig.ts +35 -1
  163. package/src/components/QueryBuilder.tsx +13 -2
  164. package/src/components/QueryBuilderExplorerPanel.tsx +20 -57
  165. package/src/components/QueryBuilderFetchStructurePanel.tsx +94 -41
  166. package/src/components/QueryBuilderFilterPanel.tsx +271 -232
  167. package/src/components/QueryBuilderFunctionsExplorerPanel.tsx +24 -68
  168. package/src/components/QueryBuilderGraphFetchTreePanel.tsx +34 -25
  169. package/src/components/QueryBuilderLambdaEditor.tsx +3 -0
  170. package/src/components/QueryBuilderMilestoneEditor.tsx +34 -34
  171. package/src/components/QueryBuilderPanelIssueCountBadge.tsx +38 -0
  172. package/src/components/QueryBuilderParameterPanel.tsx +23 -55
  173. package/src/components/QueryBuilderPostFilterPanel.tsx +245 -233
  174. package/src/components/QueryBuilderProjectionPanel.tsx +127 -154
  175. package/src/components/QueryBuilderPropertyExpressionEditor.tsx +61 -57
  176. package/src/components/QueryBuilderPropertySearchPanel.tsx +9 -9
  177. package/src/components/QueryBuilderResultModifierPanel.tsx +4 -2
  178. package/src/components/QueryBuilderResultPanel.tsx +139 -91
  179. package/src/components/QueryBuilderSetupPanel.tsx +13 -12
  180. package/src/components/QueryBuilderUnsupportedQueryEditor.tsx +4 -2
  181. package/src/components/QueryEditor.tsx +39 -1
  182. package/src/stores/QueryBuilderExplorerState.ts +22 -3
  183. package/src/stores/QueryBuilderFetchStructureState.ts +18 -2
  184. package/src/stores/QueryBuilderFilterState.ts +52 -7
  185. package/src/stores/QueryBuilderGraphFetchTreeState.ts +14 -8
  186. package/src/stores/QueryBuilderLambdaProcessor.ts +8 -0
  187. package/src/stores/QueryBuilderOperatorLoader.ts +133 -0
  188. package/src/stores/QueryBuilderOperatorsHelper.ts +35 -0
  189. package/src/stores/QueryBuilderPostFilterState.ts +47 -8
  190. package/src/stores/QueryBuilderPreviewDataHelper.ts +122 -217
  191. package/src/stores/QueryBuilderProjectionState.ts +40 -53
  192. package/src/stores/QueryBuilderPropertySearchPanelState.ts +1 -1
  193. package/src/stores/QueryBuilderResultState.ts +27 -9
  194. package/src/stores/QueryBuilderSetupState.ts +1 -1
  195. package/src/stores/QueryBuilderState.ts +35 -94
  196. package/src/stores/QueryBuilderTestUtils.ts +93 -0
  197. package/src/stores/QueryBuilderTypeaheadHelper.ts +149 -0
  198. package/src/stores/QueryBuilderValueSpecificationBuilderHelper.ts +9 -7
  199. package/src/stores/QueryEditorStore.ts +19 -3
  200. package/src/stores/QueryFunctionsExplorerState.ts +1 -11
  201. package/src/stores/QueryParametersState.ts +1 -3
  202. package/src/stores/filterOperators/QueryBuilderFilterOperator_Equal.ts +14 -36
  203. package/src/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.ts +17 -36
  204. package/src/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.ts +17 -36
  205. package/src/stores/filterOperators/QueryBuilderFilterOperator_LessThan.ts +17 -37
  206. package/src/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.ts +17 -36
  207. package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.ts +14 -34
  208. package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.ts +19 -37
  209. package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.ts +19 -37
  210. package/tsconfig.json +4 -0
@@ -14,6 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ import { useRef, useState } from 'react';
17
18
  import {
18
19
  clsx,
19
20
  CheckSquareIcon,
@@ -28,6 +29,7 @@ import {
28
29
  SearchIcon,
29
30
  ChevronDownIcon,
30
31
  ChevronRightIcon,
32
+ useDragPreviewLayer,
31
33
  } from '@finos/legend-art';
32
34
  import {
33
35
  Class,
@@ -37,9 +39,7 @@ import {
37
39
  } from '@finos/legend-graph';
38
40
  import { guaranteeNonNullable } from '@finos/legend-shared';
39
41
  import { observer } from 'mobx-react-lite';
40
- import { useEffect, useRef, useState } from 'react';
41
42
  import { useDrag } from 'react-dnd';
42
- import { getEmptyImage } from 'react-dnd-html5-backend';
43
43
  import { QUERY_BUILDER_PROPERTY_SEARCH_TYPE } from '../QueryBuilder_Const.js';
44
44
  import {
45
45
  type QueryBuilderExplorerTreeNodeData,
@@ -116,7 +116,9 @@ const QueryBuilderTreeNodeViewer = observer(
116
116
  props;
117
117
  const [isExpandable, setIsExpandable] = useState(false);
118
118
  const propertySearchPanelState = explorerState.propertySearchPanelState;
119
- const [, dragConnector, dragPreviewConnector] = useDrag(
119
+ const [, dragConnector, dragPreviewConnector] = useDrag<{
120
+ node?: QueryBuilderExplorerTreePropertyNodeData;
121
+ }>(
120
122
  () => ({
121
123
  type:
122
124
  node instanceof QueryBuilderExplorerTreePropertyNodeData
@@ -126,16 +128,17 @@ const QueryBuilderTreeNodeViewer = observer(
126
128
  ? QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.CLASS_PROPERTY
127
129
  : QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY
128
130
  : QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ROOT,
129
- item: (): { node?: QueryBuilderExplorerTreePropertyNodeData } =>
131
+ item: () =>
130
132
  node instanceof QueryBuilderExplorerTreePropertyNodeData
131
133
  ? { node }
132
134
  : {},
133
- collect: (monitor): { isDragging: boolean } => ({
135
+ collect: (monitor) => ({
134
136
  isDragging: monitor.isDragging(),
135
137
  }),
136
138
  }),
137
139
  [node],
138
140
  );
141
+ useDragPreviewLayer(dragPreviewConnector);
139
142
  const isMultiple =
140
143
  (node instanceof QueryBuilderExplorerTreePropertyNodeData &&
141
144
  (node.property.multiplicity.upperBound === undefined ||
@@ -169,6 +172,7 @@ const QueryBuilderTreeNodeViewer = observer(
169
172
  ),
170
173
  );
171
174
  if (
175
+ propertyTreeNodeData &&
172
176
  !(propertyTreeNodeData.type instanceof Class) &&
173
177
  propertyTreeNodeData.mappingData.mapped
174
178
  ) {
@@ -185,10 +189,6 @@ const QueryBuilderTreeNodeViewer = observer(
185
189
  node.parentId === pn.id,
186
190
  );
187
191
 
188
- useEffect(() => {
189
- dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
190
- }, [dragPreviewConnector]);
191
-
192
192
  return (
193
193
  <div>
194
194
  <div
@@ -32,6 +32,7 @@ import {
32
32
  import type { QueryBuilderState } from '../stores/QueryBuilderState.js';
33
33
  import type { QueryBuilderProjectionColumnState } from '../stores/QueryBuilderProjectionState.js';
34
34
  import { guaranteeNonNullable } from '@finos/legend-shared';
35
+ import { useApplicationStore } from '@finos/legend-application';
35
36
 
36
37
  const ColumnSortEditor = observer(
37
38
  (props: {
@@ -39,6 +40,7 @@ const ColumnSortEditor = observer(
39
40
  columnSort: SortColumnState;
40
41
  }) => {
41
42
  const { queryBuilderState, columnSort } = props;
43
+ const applicationStore = useApplicationStore();
42
44
  const projectionState =
43
45
  queryBuilderState.fetchStructureState.projectionState;
44
46
  const sortColumns = queryBuilderState.resultSetModifierState.sortColumns;
@@ -81,7 +83,7 @@ const ColumnSortEditor = observer(
81
83
  disabled={projectionOptions.length <= 1}
82
84
  onChange={onChange}
83
85
  value={value}
84
- darkMode={true}
86
+ darkMode={!applicationStore.TEMPORARY__isLightThemeEnabled}
85
87
  />
86
88
  <button
87
89
  className="btn--dark btn--sm query-builder__projection__options__sort__type-btn"
@@ -95,7 +97,7 @@ const ColumnSortEditor = observer(
95
97
  )}
96
98
  </button>
97
99
  <button
98
- className="query-builder__projection__options__sort__remove-btn"
100
+ className="query-builder__projection__options__sort__remove-btn btn--dark btn--caution"
99
101
  onClick={deleteColumnSort}
100
102
  tabIndex={-1}
101
103
  title={'Remove'}
@@ -25,6 +25,7 @@ import {
25
25
  CaretDownIcon,
26
26
  ContextMenu,
27
27
  clsx,
28
+ PauseCircleIcon,
28
29
  } from '@finos/legend-art';
29
30
  import { observer } from 'mobx-react-lite';
30
31
  import { flowResult } from 'mobx';
@@ -287,6 +288,61 @@ const QueryBuilderResultContextMenu = observer(
287
288
  }),
288
289
  );
289
290
 
291
+ const QueryBuilderGridResult = observer(
292
+ (props: {
293
+ executionResult: TdsExecutionResult;
294
+ queryBuilderState: QueryBuilderState;
295
+ }) => {
296
+ const { executionResult, queryBuilderState } = props;
297
+ const [cellDoubleClickedEvent, setCellDoubleClickedEvent] =
298
+ useState<CellMouseOverEvent | null>(null);
299
+ const columns = executionResult.result.columns;
300
+ const rowData = executionResult.result.rows.map((_row) => {
301
+ const row: Record<PropertyKey, unknown> = {};
302
+ const cols = executionResult.result.columns;
303
+ _row.values.forEach((value, idx) => {
304
+ // `ag-grid` shows `false` value as empty string so we have
305
+ // call `.toString()` to avoid this behavior.
306
+ // See https://github.com/finos/legend-studio/issues/1008
307
+ row[cols[idx] as string] = isBoolean(value) ? String(value) : value;
308
+ });
309
+ return row;
310
+ });
311
+
312
+ return (
313
+ <ContextMenu
314
+ content={
315
+ <QueryBuilderResultContextMenu
316
+ event={cellDoubleClickedEvent}
317
+ queryBuilderState={queryBuilderState}
318
+ />
319
+ }
320
+ menuProps={{ elevation: 7 }}
321
+ key={executionResult._UUID}
322
+ className={clsx('ag-theme-balham-dark query-builder__result__tds-grid')}
323
+ >
324
+ <AgGridReact
325
+ rowData={rowData}
326
+ onCellMouseOver={(event): void => {
327
+ setCellDoubleClickedEvent(event);
328
+ }}
329
+ >
330
+ {columns.map((colName) => (
331
+ <AgGridColumn
332
+ minWidth={50}
333
+ sortable={true}
334
+ resizable={true}
335
+ field={colName}
336
+ key={colName}
337
+ flex={1}
338
+ />
339
+ ))}
340
+ </AgGridReact>
341
+ </ContextMenu>
342
+ );
343
+ },
344
+ );
345
+
290
346
  const QueryBuilderResultValues = observer(
291
347
  (props: {
292
348
  executionResult: ExecutionResult;
@@ -294,52 +350,11 @@ const QueryBuilderResultValues = observer(
294
350
  }) => {
295
351
  const { executionResult, queryBuilderState } = props;
296
352
  if (executionResult instanceof TdsExecutionResult) {
297
- const [cellDoubleClickedEvent, setCellDoubleClickedEvent] =
298
- useState<CellMouseOverEvent | null>(null);
299
- const columns = executionResult.result.columns;
300
- const rowData = executionResult.result.rows.map((_row) => {
301
- const row: Record<PropertyKey, unknown> = {};
302
- const cols = executionResult.result.columns;
303
- _row.values.forEach((value, idx) => {
304
- // `ag-grid` shows `false` value as empty string so we have
305
- // call `.toString()` to avoid this behavior.
306
- // See https://github.com/finos/legend-studio/issues/1008
307
- row[cols[idx] as string] = isBoolean(value) ? String(value) : value;
308
- });
309
- return row;
310
- });
311
353
  return (
312
- <ContextMenu
313
- content={
314
- <QueryBuilderResultContextMenu
315
- event={cellDoubleClickedEvent}
316
- queryBuilderState={queryBuilderState}
317
- />
318
- }
319
- menuProps={{ elevation: 7 }}
320
- key={executionResult._UUID}
321
- className={clsx(
322
- 'ag-theme-balham-dark query-builder__result__tds-grid',
323
- )}
324
- >
325
- <AgGridReact
326
- rowData={rowData}
327
- onCellMouseOver={(event): void => {
328
- setCellDoubleClickedEvent(event);
329
- }}
330
- >
331
- {columns.map((colName) => (
332
- <AgGridColumn
333
- minWidth={50}
334
- sortable={true}
335
- resizable={true}
336
- field={colName}
337
- key={colName}
338
- flex={1}
339
- />
340
- ))}
341
- </AgGridReact>
342
- </ContextMenu>
354
+ <QueryBuilderGridResult
355
+ queryBuilderState={queryBuilderState}
356
+ executionResult={executionResult}
357
+ />
343
358
  );
344
359
  } else if (executionResult instanceof RawExecutionResult) {
345
360
  return (
@@ -413,27 +428,35 @@ export const QueryBuilderResultPanel = observer(
413
428
  ],
414
429
  });
415
430
  };
416
- const execute = (): void => {
431
+ const queryValidationIssues = queryBuilderState.validationIssues;
432
+ const isQueryValid =
433
+ !queryBuilderState.isQuerySupported() || !queryValidationIssues;
434
+ const runQuery = (): void => {
417
435
  if (queryParametersState.parameterStates.length) {
418
436
  queryParametersState.parameterValuesEditorState.open(
419
437
  (): Promise<void> =>
420
- flowResult(resultState.execute()).catch(
438
+ flowResult(resultState.runQuery()).catch(
421
439
  applicationStore.alertUnhandledError,
422
440
  ),
423
441
  PARAMETER_SUBMIT_ACTION.EXECUTE,
424
442
  );
425
443
  } else {
426
- flowResult(resultState.execute()).catch(
444
+ flowResult(resultState.runQuery()).catch(
427
445
  applicationStore.alertUnhandledError,
428
446
  );
429
447
  }
430
448
  };
449
+ const cancelQuery = (): void => {
450
+ resultState.setIsRunningQuery(false);
451
+ queryBuilderState.resultState.setQueryRunPromise(undefined);
452
+ };
431
453
  const generatePlan = applicationStore.guardUnhandledError(() =>
432
454
  flowResult(resultState.generatePlan(false)),
433
455
  );
434
456
  const debugPlanGeneration = applicationStore.guardUnhandledError(() =>
435
457
  flowResult(resultState.generatePlan(true)),
436
458
  );
459
+
437
460
  const changeLimit: React.ChangeEventHandler<HTMLInputElement> = (event) => {
438
461
  const val = event.target.value;
439
462
  queryBuilderState.resultState.setPreviewLimit(
@@ -469,52 +492,72 @@ export const QueryBuilderResultPanel = observer(
469
492
  type="number"
470
493
  value={resultState.previewLimit}
471
494
  onChange={changeLimit}
495
+ disabled={!isQueryValid}
472
496
  />
473
497
  </div>
474
498
  )}
475
- <button
476
- className="query-builder__result__execute-btn"
477
- onClick={execute}
478
- disabled={
479
- resultState.isExecutingQuery || resultState.isGeneratingPlan
480
- }
481
- tabIndex={-1}
482
- >
483
- <div className="query-builder__result__execute-btn__label">
484
- <PlayIcon className="query-builder__result__execute-btn__label__icon" />
485
- <div className="query-builder__result__execute-btn__label__title">
486
- Run Query
499
+ {resultState.isRunningQuery ? (
500
+ <button
501
+ className="query-builder__result__stop-btn"
502
+ onClick={cancelQuery}
503
+ tabIndex={-1}
504
+ disabled={!isQueryValid}
505
+ >
506
+ <div className="btn--dark btn--caution query-builder__result__stop-btn__label">
507
+ <PauseCircleIcon className="query-builder__result__stop-btn__label__icon" />
508
+ <div className="query-builder__result__stop-btn__label__title">
509
+ Stop
510
+ </div>
487
511
  </div>
488
- </div>
489
- <DropdownMenu
490
- className="query-builder__result__execute-btn__dropdown-btn"
491
- disabled={
492
- resultState.isExecutingQuery || resultState.isGeneratingPlan
493
- }
494
- content={
495
- <MenuContent>
496
- <MenuContentItem
497
- className="query-builder__result__execute-btn__option"
498
- onClick={generatePlan}
499
- >
500
- Generate Plan
501
- </MenuContentItem>
502
- <MenuContentItem
503
- className="query-builder__result__execute-btn__option"
504
- onClick={debugPlanGeneration}
505
- >
506
- Debug
507
- </MenuContentItem>
508
- </MenuContent>
512
+ </button>
513
+ ) : (
514
+ <button
515
+ className="query-builder__result__execute-btn"
516
+ onClick={runQuery}
517
+ tabIndex={-1}
518
+ title={
519
+ queryValidationIssues
520
+ ? `Query is not valid:\n${queryValidationIssues
521
+ .map((issue) => `\u2022 ${issue}`)
522
+ .join('\n')}`
523
+ : undefined
509
524
  }
510
- menuProps={{
511
- anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
512
- transformOrigin: { vertical: 'top', horizontal: 'right' },
513
- }}
525
+ disabled={!isQueryValid}
514
526
  >
515
- <CaretDownIcon />
516
- </DropdownMenu>
517
- </button>
527
+ <div className="query-builder__result__execute-btn__label">
528
+ <PlayIcon className="query-builder__result__execute-btn__label__icon" />
529
+ <div className="query-builder__result__execute-btn__label__title">
530
+ Run Query
531
+ </div>
532
+ </div>
533
+ <DropdownMenu
534
+ className="query-builder__result__execute-btn__dropdown-btn"
535
+ disabled={resultState.isGeneratingPlan}
536
+ content={
537
+ <MenuContent>
538
+ <MenuContentItem
539
+ className="query-builder__result__execute-btn__option"
540
+ onClick={generatePlan}
541
+ >
542
+ Generate Plan
543
+ </MenuContentItem>
544
+ <MenuContentItem
545
+ className="query-builder__result__execute-btn__option"
546
+ onClick={debugPlanGeneration}
547
+ >
548
+ Debug
549
+ </MenuContentItem>
550
+ </MenuContent>
551
+ }
552
+ menuProps={{
553
+ anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
554
+ transformOrigin: { vertical: 'top', horizontal: 'right' },
555
+ }}
556
+ >
557
+ <CaretDownIcon />
558
+ </DropdownMenu>
559
+ </button>
560
+ )}
518
561
  <DropdownMenu
519
562
  className="query-builder__result__export__dropdown"
520
563
  content={
@@ -542,19 +585,24 @@ export const QueryBuilderResultPanel = observer(
542
585
  className="query-builder__result__export__dropdown__label"
543
586
  tabIndex={-1}
544
587
  title="Export"
588
+ disabled={!isQueryValid}
545
589
  >
546
590
  Export
547
591
  </button>
548
- <div className="query-builder__result__export__dropdown__trigger">
592
+ <button
593
+ className="query-builder__result__export__dropdown__trigger"
594
+ tabIndex={-1}
595
+ disabled={!isQueryValid}
596
+ >
549
597
  <CaretDownIcon />
550
- </div>
598
+ </button>
551
599
  </DropdownMenu>
552
600
  </div>
553
601
  </div>
554
602
  <div className="panel__content">
555
603
  <PanelLoadingIndicator
556
604
  isLoading={
557
- resultState.isExecutingQuery ||
605
+ resultState.isRunningQuery ||
558
606
  resultState.isGeneratingPlan ||
559
607
  resultState.exportDataState.isInProgress
560
608
  }
@@ -21,7 +21,6 @@ import {
21
21
  PURE_ClassIcon,
22
22
  PURE_MappingIcon,
23
23
  PURE_RuntimeIcon,
24
- EyeIcon,
25
24
  ClockIcon,
26
25
  clsx,
27
26
  } from '@finos/legend-art';
@@ -46,8 +45,9 @@ import {
46
45
  } from '@finos/legend-graph';
47
46
  import {
48
47
  type PackageableElementOption,
49
- getPackageableElementOptionalFormatter,
48
+ getPackageableElementOptionFormatter,
50
49
  buildElementOption,
50
+ useApplicationStore,
51
51
  } from '@finos/legend-application';
52
52
  import { MilestoningParametersEditor } from './QueryBuilderMilestoneEditor.js';
53
53
  import { useState } from 'react';
@@ -124,8 +124,8 @@ const generateClassLabel = (
124
124
  >
125
125
  {val.name}
126
126
  </div>
127
- <EyeIcon
128
- className="query-builder__setup__config__item__class-label__btn"
127
+ <ClockIcon
128
+ className="query-builder__setup__config__item__class-label__milestoning"
129
129
  title={milestoningParameterValues}
130
130
  />
131
131
  </div>
@@ -151,6 +151,7 @@ const generateClassLabel = (
151
151
  export const QueryBuilderSetupPanel = observer(
152
152
  (props: { queryBuilderState: QueryBuilderState }) => {
153
153
  const { queryBuilderState } = props;
154
+ const applicationStore = useApplicationStore();
154
155
  const querySetupState = queryBuilderState.querySetupState;
155
156
  const [isMilestoneEditorOpened, setIsMilestoneEditorOpened] =
156
157
  useState<boolean>(false);
@@ -266,15 +267,15 @@ export const QueryBuilderSetupPanel = observer(
266
267
  options={classOptions}
267
268
  onChange={changeClass}
268
269
  value={selectedClassOption}
269
- darkMode={true}
270
+ darkMode={!applicationStore.TEMPORARY__isLightThemeEnabled}
270
271
  disabled={!isQuerySupported || querySetupState.classIsReadOnly}
271
272
  filterOption={elementFilterOption}
272
- formatOptionLabel={getPackageableElementOptionalFormatter({
273
- darkMode: true,
273
+ formatOptionLabel={getPackageableElementOptionFormatter({
274
+ darkMode: !applicationStore.TEMPORARY__isLightThemeEnabled,
274
275
  })}
275
276
  />
276
277
  <button
277
- className="btn--dark btn__icon--dark"
278
+ className="btn--dark btn__icon--dark query-builder__setup__milestoning"
278
279
  tabIndex={-1}
279
280
  onClick={(): void => setIsMilestoneEditorOpened(true)}
280
281
  disabled={!isMilestonedQuery}
@@ -302,10 +303,10 @@ export const QueryBuilderSetupPanel = observer(
302
303
  options={mappingOptions}
303
304
  onChange={changeMapping}
304
305
  value={selectedMappingOption}
305
- darkMode={true}
306
+ darkMode={!applicationStore.TEMPORARY__isLightThemeEnabled}
306
307
  filterOption={elementFilterOption}
307
- formatOptionLabel={getPackageableElementOptionalFormatter({
308
- darkMode: true,
308
+ formatOptionLabel={getPackageableElementOptionFormatter({
309
+ darkMode: !applicationStore.TEMPORARY__isLightThemeEnabled,
309
310
  })}
310
311
  />
311
312
  </div>
@@ -330,7 +331,7 @@ export const QueryBuilderSetupPanel = observer(
330
331
  options={runtimeOptions}
331
332
  onChange={changeRuntime}
332
333
  value={selectedRuntimeOption}
333
- darkMode={true}
334
+ darkMode={!applicationStore.TEMPORARY__isLightThemeEnabled}
334
335
  filterOption={runtimeFilterOption}
335
336
  />
336
337
  </div>
@@ -48,7 +48,9 @@ const QueryBuilderUnsupportedQueryEditPanel = observer(
48
48
  const { queryBuilderState } = props;
49
49
  const queryUnsupportedState = queryBuilderState.queryUnsupportedState;
50
50
  const lambdaError = queryUnsupportedState.lambdaError;
51
- const errorMessage = lambdaError ? `due to: ${lambdaError.message}` : '';
51
+ const errorMessage = lambdaError?.message
52
+ ? ` due to: ${lambdaError.message}`
53
+ : '';
52
54
  const openLambdaModal = (): void =>
53
55
  queryBuilderState.queryTextEditorState.openModal(
54
56
  QueryTextEditorMode.TEXT,
@@ -63,7 +65,7 @@ const QueryBuilderUnsupportedQueryEditPanel = observer(
63
65
  <div className="panel__content">
64
66
  <BlankPanelContent>
65
67
  <div className="query-builder__unsupported-view__main">
66
- <div className="query-builder__unsupported-view__summary">{`Can't display query in form mode ${errorMessage}`}</div>
68
+ <div className="query-builder__unsupported-view__summary">{`Can't display query in form mode${errorMessage}`}</div>
67
69
  <button
68
70
  className="btn--dark query-builder__unsupported-view__to-text-mode__btn"
69
71
  onClick={openLambdaModal}
@@ -22,6 +22,9 @@ import {
22
22
  RobotIcon,
23
23
  SaveIcon,
24
24
  BlankPanelContent,
25
+ clsx,
26
+ EmptyLightBulbIcon,
27
+ LightBulbIcon,
25
28
  } from '@finos/legend-art';
26
29
  import { getQueryParameters } from '@finos/legend-shared';
27
30
  import { observer } from 'mobx-react-lite';
@@ -108,6 +111,8 @@ const QueryExportDialogContent = observer(
108
111
  )}
109
112
  <button
110
113
  className="btn modal__footer__close-btn btn--dark"
114
+ // TODO?: we should probably annotate here why,
115
+ // when we disable this action
111
116
  disabled={!allowCreate}
112
117
  onClick={create}
113
118
  >
@@ -199,6 +204,10 @@ const QueryEditorHeaderContent = observer(() => {
199
204
  ),
200
205
  );
201
206
  };
207
+ const toggleLightDarkTheme = (): void =>
208
+ applicationStore.TEMPORARY__setIsLightThemeEnabled(
209
+ !applicationStore.TEMPORARY__isLightThemeEnabled,
210
+ );
202
211
  const saveQuery = (): void => {
203
212
  editorStore.queryBuilderState
204
213
  .saveQuery(async (lambda: RawLambda) => {
@@ -227,6 +236,20 @@ const QueryEditorHeaderContent = observer(() => {
227
236
  >
228
237
  <ExternalLinkSquareIcon />
229
238
  </button>
239
+ {applicationStore.config.options.TEMPORARY__enableThemeSwitcher && (
240
+ <button
241
+ className="query-editor__header__action query-editor__header__action--simple btn--dark"
242
+ tabIndex={-1}
243
+ title="Toggle Light/Dark Theme"
244
+ onClick={toggleLightDarkTheme}
245
+ >
246
+ {applicationStore.TEMPORARY__isLightThemeEnabled ? (
247
+ <EmptyLightBulbIcon />
248
+ ) : (
249
+ <LightBulbIcon />
250
+ )}
251
+ </button>
252
+ )}
230
253
  <button
231
254
  className="query-editor__header__action btn--dark"
232
255
  tabIndex={-1}
@@ -256,9 +279,24 @@ export const QueryEditor = observer(() => {
256
279
  );
257
280
  }, [editorStore, applicationStore]);
258
281
 
282
+ useEffect(() => {
283
+ document.body.classList.toggle(
284
+ 'light-theme',
285
+ applicationStore.TEMPORARY__isLightThemeEnabled,
286
+ );
287
+ }, [applicationStore.TEMPORARY__isLightThemeEnabled]);
288
+
259
289
  return (
260
290
  <DndProvider backend={HTML5Backend}>
261
- <div className="query-editor">
291
+ <div
292
+ className={clsx([
293
+ 'query-editor ',
294
+ {
295
+ 'query-editor--light':
296
+ applicationStore.TEMPORARY__isLightThemeEnabled,
297
+ },
298
+ ])}
299
+ >
262
300
  <div className="query-editor__header">
263
301
  <button
264
302
  className="query-editor__header__back-btn btn--dark"
@@ -50,6 +50,8 @@ import {
50
50
  EntityMappedProperty,
51
51
  Enumeration,
52
52
  DerivedProperty,
53
+ Property,
54
+ Association,
53
55
  } from '@finos/legend-graph';
54
56
  import type { QueryBuilderState } from './QueryBuilderState.js';
55
57
  import {
@@ -342,7 +344,7 @@ export const getQueryBuilderPropertyNodeData = (
342
344
  property: AbstractProperty,
343
345
  parentNode: QueryBuilderExplorerTreeNodeData,
344
346
  modelCoverageAnalysisResult: MappingModelCoverageAnalysisResult,
345
- ): QueryBuilderExplorerTreePropertyNodeData => {
347
+ ): QueryBuilderExplorerTreePropertyNodeData | undefined => {
346
348
  const mappingNodeData = generatePropertyNodeMappingData(
347
349
  property,
348
350
  parentNode.mappingData,
@@ -353,6 +355,21 @@ export const getQueryBuilderPropertyNodeData = (
353
355
  parentNode.isPartOfDerivedPropertyBranch ||
354
356
  (parentNode instanceof QueryBuilderExplorerTreePropertyNodeData &&
355
357
  parentNode.property instanceof DerivedProperty);
358
+ // NOTE: in case of association, to avoid infinite exploration path
359
+ // we will prune it, on the other hand, in circular composition case
360
+ // A has property of type B and B has property of type A
361
+ // we will allow users to explore as deeply as they wish
362
+ // See https://github.com/finos/legend-studio/issues/1172
363
+ if (
364
+ property instanceof Property &&
365
+ parentNode instanceof QueryBuilderExplorerTreePropertyNodeData &&
366
+ parentNode.property instanceof Property &&
367
+ property._OWNER instanceof Association &&
368
+ parentNode.property._OWNER instanceof Association &&
369
+ parentNode.property._OWNER === property._OWNER
370
+ ) {
371
+ return undefined;
372
+ }
356
373
  const propertyNode = new QueryBuilderExplorerTreePropertyNodeData(
357
374
  `${
358
375
  parentNode instanceof QueryBuilderExplorerTreeRootNodeData
@@ -455,8 +472,10 @@ const getQueryBuilderTreeData = (
455
472
  treeRootNode,
456
473
  modelCoverageAnalysisResult,
457
474
  );
458
- addUniqueEntry(treeRootNode.childrenIds, propertyTreeNodeData.id);
459
- nodes.set(propertyTreeNodeData.id, propertyTreeNodeData);
475
+ if (propertyTreeNodeData) {
476
+ addUniqueEntry(treeRootNode.childrenIds, propertyTreeNodeData.id);
477
+ nodes.set(propertyTreeNodeData.id, propertyTreeNodeData);
478
+ }
460
479
  });
461
480
  rootClass._subclasses.forEach((subclass) => {
462
481
  const subTypeTreeNodeData = getQueryBuilderSubTypeNodeData(