@finos/legend-query-builder 4.14.36 → 4.14.38

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. package/lib/__lib__/QueryBuilderDocumentation.d.ts +2 -1
  2. package/lib/__lib__/QueryBuilderDocumentation.d.ts.map +1 -1
  3. package/lib/__lib__/QueryBuilderDocumentation.js +1 -0
  4. package/lib/__lib__/QueryBuilderDocumentation.js.map +1 -1
  5. package/lib/components/QueryBuilder.d.ts.map +1 -1
  6. package/lib/components/QueryBuilder.js +26 -9
  7. package/lib/components/QueryBuilder.js.map +1 -1
  8. package/lib/components/QueryBuilderSideBar.d.ts.map +1 -1
  9. package/lib/components/QueryBuilderSideBar.js +3 -3
  10. package/lib/components/QueryBuilderSideBar.js.map +1 -1
  11. package/lib/components/QueryBuilderTextEditor.d.ts.map +1 -1
  12. package/lib/components/QueryBuilderTextEditor.js +17 -3
  13. package/lib/components/QueryBuilderTextEditor.js.map +1 -1
  14. package/lib/components/explorer/QueryBuilderMilestoningEditor.d.ts +5 -0
  15. package/lib/components/explorer/QueryBuilderMilestoningEditor.d.ts.map +1 -1
  16. package/lib/components/explorer/QueryBuilderMilestoningEditor.js +10 -5
  17. package/lib/components/explorer/QueryBuilderMilestoningEditor.js.map +1 -1
  18. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.d.ts.map +1 -1
  19. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js +35 -3
  20. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js.map +1 -1
  21. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  22. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +11 -1
  23. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  24. package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
  25. package/lib/components/result/QueryBuilderResultPanel.js +21 -8
  26. package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
  27. package/lib/components/workflows/ClassQueryBuilder.d.ts.map +1 -1
  28. package/lib/components/workflows/ClassQueryBuilder.js +3 -3
  29. package/lib/components/workflows/ClassQueryBuilder.js.map +1 -1
  30. package/lib/components/workflows/MappingQueryBuilder.d.ts.map +1 -1
  31. package/lib/components/workflows/MappingQueryBuilder.js +3 -3
  32. package/lib/components/workflows/MappingQueryBuilder.js.map +1 -1
  33. package/lib/components/workflows/ServiceQueryBuilder.d.ts.map +1 -1
  34. package/lib/components/workflows/ServiceQueryBuilder.js +3 -3
  35. package/lib/components/workflows/ServiceQueryBuilder.js.map +1 -1
  36. package/lib/index.css +2 -2
  37. package/lib/index.css.map +1 -1
  38. package/lib/package.json +1 -1
  39. package/lib/stores/QueryBuilderTextEditorState.d.ts +4 -1
  40. package/lib/stores/QueryBuilderTextEditorState.d.ts.map +1 -1
  41. package/lib/stores/QueryBuilderTextEditorState.js +19 -2
  42. package/lib/stores/QueryBuilderTextEditorState.js.map +1 -1
  43. package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts +16 -0
  44. package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts.map +1 -1
  45. package/lib/stores/QueryLoaderState.d.ts +2 -2
  46. package/lib/stores/QueryLoaderState.d.ts.map +1 -1
  47. package/lib/stores/QueryLoaderState.js +3 -3
  48. package/lib/stores/QueryLoaderState.js.map +1 -1
  49. package/lib/stores/explorer/QueryFunctionsExplorerState.d.ts +1 -1
  50. package/lib/stores/explorer/QueryFunctionsExplorerState.d.ts.map +1 -1
  51. package/lib/stores/explorer/QueryFunctionsExplorerState.js +2 -1
  52. package/lib/stores/explorer/QueryFunctionsExplorerState.js.map +1 -1
  53. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts +1 -0
  54. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts.map +1 -1
  55. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js +8 -0
  56. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js.map +1 -1
  57. package/lib/stores/milestoning/QueryBuilderMilestoningState.d.ts.map +1 -1
  58. package/lib/stores/milestoning/QueryBuilderMilestoningState.js +9 -3
  59. package/lib/stores/milestoning/QueryBuilderMilestoningState.js.map +1 -1
  60. package/package.json +5 -5
  61. package/src/__lib__/QueryBuilderDocumentation.ts +1 -0
  62. package/src/components/QueryBuilder.tsx +100 -17
  63. package/src/components/QueryBuilderSideBar.tsx +3 -2
  64. package/src/components/QueryBuilderTextEditor.tsx +46 -11
  65. package/src/components/explorer/QueryBuilderMilestoningEditor.tsx +60 -46
  66. package/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx +53 -3
  67. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +116 -19
  68. package/src/components/result/QueryBuilderResultPanel.tsx +84 -29
  69. package/src/components/workflows/ClassQueryBuilder.tsx +3 -2
  70. package/src/components/workflows/MappingQueryBuilder.tsx +3 -2
  71. package/src/components/workflows/ServiceQueryBuilder.tsx +7 -3
  72. package/src/stores/QueryBuilderTextEditorState.ts +20 -2
  73. package/src/stores/QueryBuilder_LegendApplicationPlugin_Extension.ts +21 -0
  74. package/src/stores/QueryLoaderState.ts +5 -7
  75. package/src/stores/explorer/QueryFunctionsExplorerState.ts +6 -2
  76. package/src/stores/fetch-structure/tds/QueryBuilderTDSState.ts +11 -0
  77. package/src/stores/milestoning/QueryBuilderMilestoningState.ts +11 -7
@@ -278,12 +278,10 @@ const AllVersionsInRangelMilestoningParametersEditor = observer(
278
278
  },
279
279
  );
280
280
 
281
- export const MilestoningParametersEditor = observer(
281
+ export const MilestoningParametersEditorContent = observer(
282
282
  (props: { queryBuilderState: QueryBuilderState }) => {
283
283
  const { queryBuilderState } = props;
284
- const applicationStore = queryBuilderState.applicationStore;
285
284
  const milestoningState = queryBuilderState.milestoningState;
286
- const close = (): void => milestoningState.setShowMilestoningEditor(false);
287
285
  const isCompatibleMilestoningParameter = (
288
286
  variable: VariableExpression,
289
287
  ): boolean =>
@@ -292,6 +290,62 @@ export const MilestoningParametersEditor = observer(
292
290
  variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.DATE ||
293
291
  variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.DATETIME;
294
292
 
293
+ return (
294
+ <>
295
+ {milestoningState.isCurrentClassMilestoned && (
296
+ <PanelFormBooleanField
297
+ isReadOnly={false}
298
+ value={milestoningState.isAllVersionsEnabled}
299
+ name="all Versions"
300
+ prompt="Query All Milestoned Versions of the Root Class"
301
+ update={(value: boolean | undefined): void =>
302
+ milestoningState.setAllVersions(value)
303
+ }
304
+ />
305
+ )}
306
+ {milestoningState.isAllVersionsEnabled &&
307
+ milestoningState.isCurrentClassSupportsVersionsInRange && (
308
+ <>
309
+ <PanelFormBooleanField
310
+ isReadOnly={false}
311
+ value={milestoningState.isAllVersionsInRangeEnabled}
312
+ name=" All Versions In Range"
313
+ prompt="Optionally apply a date range to get All Versions for"
314
+ update={(value: boolean | undefined): void =>
315
+ milestoningState.setAllVersionsInRange(value)
316
+ }
317
+ />
318
+
319
+ {milestoningState.isAllVersionsInRangeEnabled && (
320
+ <AllVersionsInRangelMilestoningParametersEditor
321
+ queryBuilderState={queryBuilderState}
322
+ />
323
+ )}
324
+ </>
325
+ )}
326
+ <TemporalMilestoningEditor queryBuilderState={queryBuilderState} />
327
+ <PanelFormSection>
328
+ <div className="panel__content__form__section__header__label">
329
+ List of compatible milestoning parameters
330
+ </div>
331
+ </PanelFormSection>
332
+ <div className="panel__content__form__section__list__items">
333
+ <VariableSelector
334
+ queryBuilderState={queryBuilderState}
335
+ filterBy={isCompatibleMilestoningParameter}
336
+ />
337
+ </div>
338
+ </>
339
+ );
340
+ },
341
+ );
342
+
343
+ export const MilestoningParametersEditor = observer(
344
+ (props: { queryBuilderState: QueryBuilderState }) => {
345
+ const { queryBuilderState } = props;
346
+ const applicationStore = queryBuilderState.applicationStore;
347
+ const milestoningState = queryBuilderState.milestoningState;
348
+ const close = (): void => milestoningState.setShowMilestoningEditor(false);
295
349
  return (
296
350
  <Dialog
297
351
  open={milestoningState.showMilestoningEditor}
@@ -310,49 +364,9 @@ export const MilestoningParametersEditor = observer(
310
364
  >
311
365
  <ModalHeader title="Milestoning Parameters" />
312
366
  <ModalBody className="query-builder__variables__modal__body">
313
- {milestoningState.isCurrentClassMilestoned && (
314
- <PanelFormBooleanField
315
- isReadOnly={false}
316
- value={milestoningState.isAllVersionsEnabled}
317
- name="all Versions"
318
- prompt="Query All Milestoned Versions of the Root Class"
319
- update={(value: boolean | undefined): void =>
320
- milestoningState.setAllVersions(value)
321
- }
322
- />
323
- )}
324
- {milestoningState.isAllVersionsEnabled &&
325
- milestoningState.isCurrentClassSupportsVersionsInRange && (
326
- <>
327
- <PanelFormBooleanField
328
- isReadOnly={false}
329
- value={milestoningState.isAllVersionsInRangeEnabled}
330
- name=" All Versions In Range"
331
- prompt="Optionally apply a date range to get All Versions for"
332
- update={(value: boolean | undefined): void =>
333
- milestoningState.setAllVersionsInRange(value)
334
- }
335
- />
336
-
337
- {milestoningState.isAllVersionsInRangeEnabled && (
338
- <AllVersionsInRangelMilestoningParametersEditor
339
- queryBuilderState={queryBuilderState}
340
- />
341
- )}
342
- </>
343
- )}
344
- <TemporalMilestoningEditor queryBuilderState={queryBuilderState} />
345
- <PanelFormSection>
346
- <div className="panel__content__form__section__header__label">
347
- List of compatible milestoning parameters
348
- </div>
349
- </PanelFormSection>
350
- <div className="panel__content__form__section__list__items">
351
- <VariableSelector
352
- queryBuilderState={queryBuilderState}
353
- filterBy={isCompatibleMilestoningParameter}
354
- />
355
- </div>
367
+ <MilestoningParametersEditorContent
368
+ queryBuilderState={queryBuilderState}
369
+ />
356
370
  </ModalBody>
357
371
  <ModalFooter>
358
372
  <ModalFooterButton text="Close" onClick={close} type="secondary" />
@@ -48,7 +48,7 @@ import { useApplicationStore } from '@finos/legend-application';
48
48
  import type { QueryBuilderTDSState } from '../../stores/fetch-structure/tds/QueryBuilderTDSState.js';
49
49
  import type { QueryBuilderTDSColumnState } from '../../stores/fetch-structure/tds/QueryBuilderTDSColumnState.js';
50
50
  import { COLUMN_SORT_TYPE } from '../../graph/QueryBuilderMetaModelConst.js';
51
- import { useCallback, useEffect, useState } from 'react';
51
+ import { useCallback, useEffect, useRef, useState } from 'react';
52
52
  import type { QueryBuilderProjectionColumnState } from '../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
53
53
  import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
54
54
  import { VariableSelector } from '../shared/QueryBuilderVariableSelector.js';
@@ -65,6 +65,7 @@ import {
65
65
  type QueryBuilderVariableDragSource,
66
66
  } from '../shared/BasicValueSpecificationEditor.js';
67
67
  import { useDrop } from 'react-dnd';
68
+ import { MilestoningParametersEditorContent } from '../explorer/QueryBuilderMilestoningEditor.js';
68
69
 
69
70
  const ColumnSortEditor = observer(
70
71
  (props: {
@@ -270,6 +271,31 @@ export const QueryResultModifierModal = observer(
270
271
  deepClone(watermarkState.value),
271
272
  );
272
273
 
274
+ //milestoning config
275
+ const milestoningState = tdsState.queryBuilderState.milestoningState;
276
+ const businessDate = useRef(milestoningState.businessDate);
277
+ const processingDate = useRef(milestoningState.processingDate);
278
+ const isAllVersionsEnabled = useRef(milestoningState.isAllVersionsEnabled);
279
+ const isAllVersionsInRangeEnabled = useRef(
280
+ milestoningState.isAllVersionsInRangeEnabled,
281
+ );
282
+ const startDate = useRef(milestoningState.startDate);
283
+ const endDate = useRef(milestoningState.endDate);
284
+
285
+ const resetMilestoningToInitial = (): void => {
286
+ if (isAllVersionsInRangeEnabled.current) {
287
+ milestoningState.setAllVersionsInRange(
288
+ isAllVersionsInRangeEnabled.current,
289
+ );
290
+ milestoningState.setStartDate(startDate.current);
291
+ milestoningState.setEndDate(endDate.current);
292
+ } else {
293
+ milestoningState.setAllVersions(isAllVersionsEnabled.current);
294
+ }
295
+ milestoningState.setBusinessDate(businessDate.current);
296
+ milestoningState.setProcessingDate(processingDate.current);
297
+ };
298
+
273
299
  // Sync temp state with tdsState when modal is opened/closed
274
300
  useEffect(() => {
275
301
  setSortColumns(cloneSortColumnStateArray(stateSortColumns));
@@ -287,7 +313,10 @@ export const QueryResultModifierModal = observer(
287
313
  ]);
288
314
 
289
315
  // Handle user actions
290
- const closeModal = (): void => resultSetModifierState.setShowModal(false);
316
+ const closeModal = (): void => {
317
+ resetMilestoningToInitial();
318
+ resultSetModifierState.setShowModal(false);
319
+ };
291
320
  const applyChanges = (): void => {
292
321
  resultSetModifierState.setSortColumns(sortColumns);
293
322
  resultSetModifierState.setDistinct(distinct);
@@ -299,6 +328,13 @@ export const QueryResultModifierModal = observer(
299
328
  }
300
329
  resultSetModifierState.setShowModal(false);
301
330
  watermarkState.setValue(watermarkValue);
331
+ businessDate.current = milestoningState.businessDate;
332
+ processingDate.current = milestoningState.processingDate;
333
+ isAllVersionsEnabled.current = milestoningState.isAllVersionsEnabled;
334
+ isAllVersionsInRangeEnabled.current =
335
+ milestoningState.isAllVersionsInRangeEnabled;
336
+ startDate.current = milestoningState.startDate;
337
+ endDate.current = milestoningState.endDate;
302
338
  };
303
339
 
304
340
  const handleLimitResultsChange: React.ChangeEventHandler<
@@ -408,9 +444,23 @@ export const QueryResultModifierModal = observer(
408
444
  }
409
445
  className="editor-modal query-builder__projection__modal"
410
446
  >
411
- <ModalHeader title="Result Set Modifier" />
447
+ <ModalHeader title="Query Options" />
412
448
  <ModalBody className="query-builder__projection__modal__body">
413
449
  <div className="query-builder__projection__options">
450
+ {tdsState.queryBuilderState.milestoningState
451
+ .isMilestonedQuery && (
452
+ <>
453
+ <div className="query-builder__projection__options__section-name">
454
+ Milestoning
455
+ </div>
456
+ <MilestoningParametersEditorContent
457
+ queryBuilderState={tdsState.queryBuilderState}
458
+ />
459
+ <div className="query-builder__projection__options__section-name">
460
+ Other
461
+ </div>
462
+ </>
463
+ )}
414
464
  <ColumnsSortEditor
415
465
  projectionColumns={tdsState.projectionColumns}
416
466
  sortColumns={sortColumns}
@@ -1148,27 +1148,118 @@ export const QueryBuilderTDSPanel = observer(
1148
1148
  >
1149
1149
  <div className="query-builder__projection__result-modifier-prompt__header">
1150
1150
  <button
1151
- className="query-builder__projection__result-modifier-prompt__header__label"
1151
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1152
1152
  onClick={openResultSetModifierEditor}
1153
- title="Configure result set modifiers..."
1153
+ title="Configure Query Options..."
1154
1154
  >
1155
1155
  <CogIcon className="query-builder__projection__result-modifier-prompt__header__label__icon" />
1156
1156
  <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1157
- Query Options
1157
+ {tdsState.isQueryOptionsSet
1158
+ ? 'Query Options'
1159
+ : 'Set Query Options'}
1158
1160
  </div>
1159
1161
  </button>
1162
+ <div className="query-builder__projection__result-modifier-prompt__divider">
1163
+ {tdsState.isQueryOptionsSet && ' - '}
1164
+ </div>
1165
+ {tdsState.queryBuilderState.milestoningState.businessDate && (
1166
+ <div className="query-builder__projection__result-modifier-prompt__group">
1167
+ <div className="query-builder__projection__result-modifier-prompt__group__label">
1168
+ Business Date
1169
+ </div>
1170
+ <button
1171
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1172
+ onClick={openResultSetModifierEditor}
1173
+ >
1174
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1175
+ {getNameOfValueSpecification(
1176
+ tdsState.queryBuilderState.milestoningState
1177
+ .businessDate,
1178
+ tdsState.queryBuilderState,
1179
+ )}
1180
+ </div>
1181
+ </button>
1182
+ </div>
1183
+ )}
1184
+ {tdsState.queryBuilderState.milestoningState.processingDate && (
1185
+ <div className="query-builder__projection__result-modifier-prompt__group">
1186
+ <div className="query-builder__projection__result-modifier-prompt__group__label">
1187
+ Processing Date
1188
+ </div>
1189
+ <button
1190
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1191
+ onClick={openResultSetModifierEditor}
1192
+ >
1193
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1194
+ {getNameOfValueSpecification(
1195
+ tdsState.queryBuilderState.milestoningState
1196
+ .processingDate,
1197
+ tdsState.queryBuilderState,
1198
+ )}
1199
+ </div>
1200
+ </button>
1201
+ </div>
1202
+ )}
1203
+ {tdsState.queryBuilderState.milestoningState
1204
+ .isAllVersionsEnabled &&
1205
+ !tdsState.queryBuilderState.milestoningState
1206
+ .isAllVersionsInRangeEnabled && (
1207
+ <div className="query-builder__projection__result-modifier-prompt__group">
1208
+ <div className="query-builder__projection__result-modifier-prompt__group__label">
1209
+ All Versions
1210
+ </div>
1211
+ <button
1212
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1213
+ onClick={openResultSetModifierEditor}
1214
+ >
1215
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1216
+ Yes
1217
+ </div>
1218
+ </button>
1219
+ </div>
1220
+ )}
1221
+ {tdsState.queryBuilderState.milestoningState
1222
+ .isAllVersionsInRangeEnabled &&
1223
+ tdsState.queryBuilderState.milestoningState.startDate &&
1224
+ tdsState.queryBuilderState.milestoningState.endDate && (
1225
+ <div className="query-builder__projection__result-modifier-prompt__group">
1226
+ <div className="query-builder__projection__result-modifier-prompt__group__label">
1227
+ All Versions
1228
+ </div>
1229
+ <button
1230
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1231
+ onClick={openResultSetModifierEditor}
1232
+ >
1233
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1234
+ (
1235
+ {getNameOfValueSpecification(
1236
+ tdsState.queryBuilderState.milestoningState.startDate,
1237
+ tdsState.queryBuilderState,
1238
+ )}{' '}
1239
+ -{' '}
1240
+ {getNameOfValueSpecification(
1241
+ tdsState.queryBuilderState.milestoningState.endDate,
1242
+ tdsState.queryBuilderState,
1243
+ )}
1244
+ )
1245
+ </div>
1246
+ </button>
1247
+ </div>
1248
+ )}
1160
1249
  </div>
1161
1250
  {tdsState.resultSetModifierState.limit && (
1162
1251
  <div className="query-builder__projection__result-modifier-prompt__group">
1163
1252
  <div className="query-builder__projection__result-modifier-prompt__group__label">
1164
1253
  Max Rows
1165
1254
  </div>
1166
- <div
1167
- className="query-builder__projection__result-modifier-prompt__group__content"
1255
+ <button
1256
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1168
1257
  onClick={openResultSetModifierEditor}
1169
1258
  >
1170
- {tdsState.resultSetModifierState.limit}
1171
- </div>
1259
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1260
+ {tdsState.resultSetModifierState.limit}
1261
+ </div>
1262
+ </button>
1172
1263
  </div>
1173
1264
  )}
1174
1265
  {tdsState.resultSetModifierState.distinct && (
@@ -1176,12 +1267,14 @@ export const QueryBuilderTDSPanel = observer(
1176
1267
  <div className="query-builder__projection__result-modifier-prompt__group__label">
1177
1268
  Eliminate Duplicate Rows
1178
1269
  </div>
1179
- <div
1180
- className="query-builder__projection__result-modifier-prompt__group__content"
1270
+ <button
1271
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1181
1272
  onClick={openResultSetModifierEditor}
1182
1273
  >
1183
- Yes
1184
- </div>
1274
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1275
+ Yes
1276
+ </div>
1277
+ </button>
1185
1278
  </div>
1186
1279
  )}
1187
1280
  {tdsState.resultSetModifierState.sortColumns.length > 0 && (
@@ -1191,13 +1284,15 @@ export const QueryBuilderTDSPanel = observer(
1191
1284
  </div>
1192
1285
  {tdsState.resultSetModifierState.sortColumns.map(
1193
1286
  (columnState) => (
1194
- <div
1195
- className="query-builder__projection__result-modifier-prompt__group__content"
1287
+ <button
1196
1288
  key={columnState.columnState.uuid}
1289
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1197
1290
  onClick={openResultSetModifierEditor}
1198
1291
  >
1199
- {`${columnState.columnState.columnName} ${columnState.sortType}`}
1200
- </div>
1292
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1293
+ {`${columnState.columnState.columnName} ${columnState.sortType}`}
1294
+ </div>
1295
+ </button>
1201
1296
  ),
1202
1297
  )}
1203
1298
  </div>
@@ -1207,12 +1302,14 @@ export const QueryBuilderTDSPanel = observer(
1207
1302
  <div className="query-builder__projection__result-modifier-prompt__group__label">
1208
1303
  Slice
1209
1304
  </div>
1210
- <div
1211
- className="query-builder__projection__result-modifier-prompt__group__content"
1305
+ <button
1306
+ className="query-builder__projection__result-modifier-prompt__header__label editable-value"
1212
1307
  onClick={openResultSetModifierEditor}
1213
1308
  >
1214
- {`${tdsState.resultSetModifierState.slice[0]},${tdsState.resultSetModifierState.slice[1]}`}
1215
- </div>
1309
+ <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1310
+ {`${tdsState.resultSetModifierState.slice[0]},${tdsState.resultSetModifierState.slice[1]}`}
1311
+ </div>
1312
+ </button>
1216
1313
  </div>
1217
1314
  )}
1218
1315
  {tdsState.queryBuilderState.watermarkState.value && (
@@ -16,7 +16,6 @@
16
16
 
17
17
  import {
18
18
  BlankPanelContent,
19
- PanelLoadingIndicator,
20
19
  PlayIcon,
21
20
  DropdownMenu,
22
21
  MenuContent,
@@ -37,6 +36,14 @@ import {
37
36
  PanelDivider,
38
37
  SquareIcon,
39
38
  CheckSquareIcon,
39
+ MenuContentItemIcon,
40
+ MenuContentItemLabel,
41
+ ChartIcon,
42
+ CsvIcon,
43
+ DebugIcon,
44
+ ReportIcon,
45
+ CubesLoadingIndicatorIcon,
46
+ CubesLoadingIndicator,
40
47
  } from '@finos/legend-art';
41
48
  import { observer } from 'mobx-react-lite';
42
49
  import { flowResult } from 'mobx';
@@ -306,6 +313,31 @@ export const QueryBuilderResultPanel = observer(
306
313
  !queryBuilderState.isLocalModeEnabled,
307
314
  );
308
315
  };
316
+
317
+ const extraExportMenuContentItems = applicationStore.pluginManager
318
+ .getApplicationPlugins()
319
+ .flatMap(
320
+ (plugin) =>
321
+ (
322
+ plugin as QueryBuilder_LegendApplicationPlugin_Extension
323
+ ).getExtraQueryBuilderExportMenuActionConfigurations?.() ?? [],
324
+ )
325
+ .map((item) => (
326
+ <MenuContentItem
327
+ key={item.key}
328
+ title={item.title ?? ''}
329
+ onClick={() => {
330
+ item.onClick(queryBuilderState);
331
+ }}
332
+ >
333
+ {item.icon && <MenuContentItemIcon>{item.icon}</MenuContentItemIcon>}
334
+ <MenuContentItemLabel>{item.label}</MenuContentItemLabel>
335
+ </MenuContentItem>
336
+ ));
337
+
338
+ const isLoading =
339
+ resultState.isRunningQuery || resultState.isGeneratingPlan;
340
+
309
341
  return (
310
342
  <div
311
343
  data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_PANEL}
@@ -355,7 +387,7 @@ export const QueryBuilderResultPanel = observer(
355
387
 
356
388
  <div className="panel__header">
357
389
  <div className="panel__header__title">
358
- <div className="panel__header__title__label">result</div>
390
+ <div className="panel__header__title__label">results</div>
359
391
  {executedSql && (
360
392
  <Button
361
393
  onClick={() => setShowSqlModal(true)}
@@ -429,7 +461,7 @@ export const QueryBuilderResultPanel = observer(
429
461
  {allowSettingPreviewLimit && (
430
462
  <div className="query-builder__result__limit">
431
463
  <div className="query-builder__result__limit__label">
432
- preview limit
464
+ preview row limit
433
465
  </div>
434
466
  <input
435
467
  ref={inputRef}
@@ -448,22 +480,20 @@ export const QueryBuilderResultPanel = observer(
448
480
  <div className="query-builder__result__execute-btn btn__dropdown-combo btn__dropdown-combo--primary">
449
481
  {resultState.isRunningQuery ? (
450
482
  <button
451
- className="btn__dropdown-combo__canceler"
483
+ className="btn__dropdown-combo__canceler query-builder__result__execute-btn__btn"
452
484
  onClick={cancelQuery}
453
485
  tabIndex={-1}
454
486
  disabled={!isQueryValid}
455
487
  >
456
- <div className="btn--dark btn--caution btn__dropdown-combo__canceler__label">
457
- <PauseCircleIcon className="btn__dropdown-combo__canceler__label__icon" />
458
- <div className="btn__dropdown-combo__canceler__label__title">
459
- Stop
460
- </div>
488
+ <div className="btn--dark btn--caution btn__dropdown-combo__canceler__label query-builder__result__execute-btn__btn">
489
+ <PauseCircleIcon />
490
+ Stop
461
491
  </div>
462
492
  </button>
463
493
  ) : (
464
494
  <>
465
495
  <button
466
- className="btn__dropdown-combo__label"
496
+ className="btn__dropdown-combo__label query-builder__result__execute-btn__btn query-builder__result__execute-btn__btn--green"
467
497
  onClick={runQuery}
468
498
  tabIndex={-1}
469
499
  title={
@@ -475,13 +505,11 @@ export const QueryBuilderResultPanel = observer(
475
505
  }
476
506
  disabled={isRunQueryDisabled}
477
507
  >
478
- <PlayIcon className="btn__dropdown-combo__label__icon" />
479
- <div className="btn__dropdown-combo__label__title">
480
- Run Query
481
- </div>
508
+ <PlayIcon />
509
+ Run Query
482
510
  </button>
483
511
  <DropdownMenu
484
- className="btn__dropdown-combo__dropdown-btn"
512
+ className="btn__dropdown-combo__dropdown-btn query-builder__result__execute-btn__btn query-builder__result__execute-btn__btn--green"
485
513
  disabled={isRunQueryDisabled}
486
514
  content={
487
515
  <MenuContent>
@@ -490,14 +518,22 @@ export const QueryBuilderResultPanel = observer(
490
518
  onClick={generatePlan}
491
519
  disabled={isRunQueryDisabled}
492
520
  >
493
- Generate Plan
521
+ <MenuContentItemIcon>
522
+ <ReportIcon />
523
+ </MenuContentItemIcon>
524
+ <MenuContentItemLabel>
525
+ Generate Plan
526
+ </MenuContentItemLabel>
494
527
  </MenuContentItem>
495
528
  <MenuContentItem
496
529
  className="btn__dropdown-combo__option"
497
530
  onClick={debugPlanGeneration}
498
531
  disabled={isRunQueryDisabled}
499
532
  >
500
- Debug
533
+ <MenuContentItemIcon>
534
+ <DebugIcon />
535
+ </MenuContentItemIcon>
536
+ <MenuContentItemLabel>Debug</MenuContentItemLabel>
501
537
  </MenuContentItem>
502
538
  </MenuContent>
503
539
  }
@@ -522,14 +558,15 @@ export const QueryBuilderResultPanel = observer(
522
558
  ).map((format) => (
523
559
  <MenuContentItem
524
560
  key={format}
525
- className="query-builder__result__export__dropdown__menu__item"
526
561
  onClick={(): void => confirmExport(format)}
527
562
  >
528
- {format}
563
+ <MenuContentItemIcon>
564
+ <CsvIcon />
565
+ </MenuContentItemIcon>
566
+ <MenuContentItemLabel>{format}</MenuContentItemLabel>
529
567
  </MenuContentItem>
530
568
  ))}
531
569
  <MenuContentItem
532
- className="query-builder__result__export__dropdown__menu__item"
533
570
  onClick={(): void =>
534
571
  resultState.setIsQueryUsageViewerOpened(true)
535
572
  }
@@ -538,8 +575,12 @@ export const QueryBuilderResultPanel = observer(
538
575
  !isExtraQueryUsageOptionsConfigured
539
576
  }
540
577
  >
541
- Query Code Snippets...
578
+ <MenuContentItemIcon>
579
+ <ChartIcon />
580
+ </MenuContentItemIcon>
581
+ <MenuContentItemLabel>Others...</MenuContentItemLabel>
542
582
  </MenuContentItem>
583
+ {extraExportMenuContentItems}
543
584
  </MenuContent>
544
585
  }
545
586
  menuProps={{
@@ -558,20 +599,34 @@ export const QueryBuilderResultPanel = observer(
558
599
  {resultState.isQueryUsageViewerOpened && (
559
600
  <QueryUsageViewer resultState={resultState} />
560
601
  )}
602
+ {applicationStore.pluginManager
603
+ .getApplicationPlugins()
604
+ .flatMap(
605
+ (plugin) =>
606
+ (
607
+ plugin as QueryBuilder_LegendApplicationPlugin_Extension
608
+ ).getExtraQueryBuilderExportMenuActionConfigurations?.() ??
609
+ [],
610
+ )
611
+ .map((item) => (
612
+ <div key={item.key}>
613
+ {item.renderExtraComponent
614
+ ? item.renderExtraComponent(queryBuilderState)
615
+ : undefined}
616
+ </div>
617
+ ))}
561
618
  </div>
562
619
  </div>
563
- <PanelContent>
564
- <PanelLoadingIndicator
565
- isLoading={
566
- resultState.isRunningQuery || resultState.isGeneratingPlan
567
- }
568
- />
569
- {!executionResult && (
620
+ <PanelContent className="query-builder__result__content">
621
+ <CubesLoadingIndicator isLoading={isLoading}>
622
+ <CubesLoadingIndicatorIcon />
623
+ </CubesLoadingIndicator>
624
+ {!executionResult && !isLoading && (
570
625
  <BlankPanelContent>
571
626
  Build or load a valid query first
572
627
  </BlankPanelContent>
573
628
  )}
574
- {executionResult && (
629
+ {executionResult && !isLoading && (
575
630
  <div className="query-builder__result__values">
576
631
  <QueryBuilderResultValues
577
632
  executionResult={executionResult}
@@ -17,6 +17,7 @@
17
17
  import {
18
18
  CustomSelectorInput,
19
19
  PanelHeader,
20
+ compareLabelFn,
20
21
  createFilter,
21
22
  } from '@finos/legend-art';
22
23
  import { observer } from 'mobx-react-lite';
@@ -71,7 +72,7 @@ const ClassQueryBuilderSetupPanelContent = observer(
71
72
  : []
72
73
  )
73
74
  .map(buildElementOption)
74
- .sort((a, b) => a.label.localeCompare(b.label));
75
+ .sort(compareLabelFn);
75
76
  const selectedMappingOption = queryBuilderState.executionContextState
76
77
  .mapping
77
78
  ? buildElementOption(queryBuilderState.executionContextState.mapping)
@@ -107,7 +108,7 @@ const ClassQueryBuilderSetupPanelContent = observer(
107
108
  new RuntimePointer(PackageableElementExplicitReference.create(rt)),
108
109
  )
109
110
  .map(buildRuntimeValueOption)
110
- .sort((a, b) => a.label.localeCompare(b.label));
111
+ .sort(compareLabelFn);
111
112
  const selectedRuntimeOption = queryBuilderState.executionContextState
112
113
  .runtimeValue
113
114
  ? buildRuntimeValueOption(