@finos/legend-query-builder 4.14.48 → 4.14.50

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. package/lib/components/QueryBuilderConstantExpressionPanel.d.ts.map +1 -1
  2. package/lib/components/QueryBuilderConstantExpressionPanel.js +3 -4
  3. package/lib/components/QueryBuilderConstantExpressionPanel.js.map +1 -1
  4. package/lib/components/QueryBuilderParametersPanel.d.ts.map +1 -1
  5. package/lib/components/QueryBuilderParametersPanel.js +20 -2
  6. package/lib/components/QueryBuilderParametersPanel.js.map +1 -1
  7. package/lib/components/QueryBuilderSideBar.d.ts.map +1 -1
  8. package/lib/components/QueryBuilderSideBar.js +4 -11
  9. package/lib/components/QueryBuilderSideBar.js.map +1 -1
  10. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts +2 -1
  11. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  12. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +56 -35
  13. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  14. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  15. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +11 -3
  16. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  17. package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
  18. package/lib/components/result/QueryBuilderResultPanel.js +2 -1
  19. package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
  20. package/lib/components/shared/QueryBuilderVariableSelector.d.ts.map +1 -1
  21. package/lib/components/shared/QueryBuilderVariableSelector.js +8 -1
  22. package/lib/components/shared/QueryBuilderVariableSelector.js.map +1 -1
  23. package/lib/index.css +17 -1
  24. package/lib/index.css.map +1 -1
  25. package/lib/package.json +1 -1
  26. package/lib/stores/QueryBuilderValueSpecificationHelper.js +1 -1
  27. package/lib/stores/QueryBuilderValueSpecificationHelper.js.map +1 -1
  28. package/lib/stores/milestoning/QueryBuilderMilestoningState.d.ts +3 -0
  29. package/lib/stores/milestoning/QueryBuilderMilestoningState.d.ts.map +1 -1
  30. package/lib/stores/milestoning/QueryBuilderMilestoningState.js +40 -0
  31. package/lib/stores/milestoning/QueryBuilderMilestoningState.js.map +1 -1
  32. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +1 -0
  33. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
  34. package/lib/stores/shared/ValueSpecificationEditorHelper.js +7 -1
  35. package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
  36. package/package.json +5 -5
  37. package/src/components/QueryBuilderConstantExpressionPanel.tsx +13 -4
  38. package/src/components/QueryBuilderParametersPanel.tsx +55 -0
  39. package/src/components/QueryBuilderSideBar.tsx +0 -20
  40. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +143 -78
  41. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +22 -6
  42. package/src/components/result/QueryBuilderResultPanel.tsx +9 -1
  43. package/src/components/shared/QueryBuilderVariableSelector.tsx +22 -0
  44. package/src/stores/QueryBuilderValueSpecificationHelper.ts +1 -1
  45. package/src/stores/milestoning/QueryBuilderMilestoningState.ts +54 -0
  46. package/src/stores/shared/ValueSpecificationEditorHelper.ts +11 -0
@@ -18,7 +18,6 @@ import {
18
18
  CustomSelectorInput,
19
19
  createFilter,
20
20
  CogIcon,
21
- ClockIcon,
22
21
  clsx,
23
22
  PanelHeader,
24
23
  compareLabelFn,
@@ -34,7 +33,6 @@ import {
34
33
  LATEST_DATE,
35
34
  PrimitiveInstanceValue,
36
35
  VariableExpression,
37
- getMilestoneTemporalStereotype,
38
36
  PackageableElementExplicitReference,
39
37
  RuntimePointer,
40
38
  VARIABLE_REFERENCE_TOKEN,
@@ -74,23 +72,11 @@ const generateClassLabel = (
74
72
  val: Class,
75
73
  queryBuilderState: QueryBuilderState,
76
74
  ): React.ReactNode => {
77
- const milestoneStereotype = getMilestoneTemporalStereotype(
78
- val,
79
- queryBuilderState.graphManagerState.graph,
80
- );
81
-
82
75
  const isDeprecatedClass = isElementDeprecated(
83
76
  val,
84
77
  queryBuilderState.graphManagerState.graph,
85
78
  );
86
79
 
87
- let milestoningTooltipText: string | undefined;
88
- if (milestoneStereotype) {
89
- milestoningTooltipText = queryBuilderState.milestoningState
90
- .getMilestoningImplementation(milestoneStereotype)
91
- .getMilestoningToolTipText();
92
- }
93
-
94
80
  return (
95
81
  <div
96
82
  className={clsx('query-builder__setup__class-option-label', {
@@ -101,12 +87,6 @@ const generateClassLabel = (
101
87
  <div className="query-builder__setup__class-option-label__name">
102
88
  {val.name}
103
89
  </div>
104
- {milestoningTooltipText && (
105
- <ClockIcon
106
- className="query-builder__setup__class-option-label__milestoning"
107
- title={`This class is milestoned:\n${milestoningTooltipText}`}
108
- />
109
- )}
110
90
  </div>
111
91
  );
112
92
  };
@@ -47,6 +47,7 @@ import {
47
47
  MenuContentItemIcon,
48
48
  MenuContentItemLabel,
49
49
  PanelLoadingIndicator,
50
+ RefreshIcon,
50
51
  } from '@finos/legend-art';
51
52
  import {
52
53
  type ValueSpecification,
@@ -69,7 +70,6 @@ import React, {
69
70
  useState,
70
71
  } from 'react';
71
72
  import { useDrop, useDrag, useDragLayer } from 'react-dnd';
72
- import { QueryBuilderAggregateColumnState } from '../../stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.js';
73
73
  import type { QueryBuilderPostFilterOperator } from '../../stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterOperator.js';
74
74
  import {
75
75
  type QueryBuilderPostFilterTreeNodeData,
@@ -110,6 +110,10 @@ import {
110
110
  import type { QueryBuilderTDSColumnState } from '../../stores/fetch-structure/tds/QueryBuilderTDSColumnState.js';
111
111
  import { QueryBuilderTelemetryHelper } from '../../__lib__/QueryBuilderTelemetryHelper.js';
112
112
  import { QueryBuilderPanelIssueCountBadge } from '../shared/QueryBuilderPanelIssueCountBadge.js';
113
+ import {
114
+ QueryBuilderPostFilterOperator_In,
115
+ QueryBuilderPostFilterOperator_NotIn,
116
+ } from '../../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js';
113
117
 
114
118
  const QueryBuilderPostFilterConditionContextMenu = observer(
115
119
  forwardRef<
@@ -213,18 +217,21 @@ const QueryBuilderPostFilterGroupConditionEditor = observer(
213
217
  export const QueryBuilderColumnBadge = observer(
214
218
  (props: {
215
219
  colState: QueryBuilderTDSColumnState;
216
- onColumnChange: (
217
- columnState: QueryBuilderProjectionColumnState,
218
- ) => Promise<void>;
220
+ onColumnChange?:
221
+ | ((columnState: QueryBuilderProjectionColumnState) => Promise<void>)
222
+ | undefined;
223
+ removeColumn?: () => void;
219
224
  }) => {
220
- const { colState, onColumnChange } = props;
225
+ const { colState, onColumnChange, removeColumn } = props;
221
226
  const applicationStore = useApplicationStore();
222
227
  const type = colState.getColumnType();
223
- const handleDrop = useCallback(
224
- (item: QueryBuilderProjectionColumnDragSource): Promise<void> =>
225
- onColumnChange(item.columnState),
226
- [onColumnChange],
227
- );
228
+ const handleDrop = onColumnChange
229
+ ? useCallback(
230
+ (item: QueryBuilderProjectionColumnDragSource): Promise<void> =>
231
+ onColumnChange(item.columnState),
232
+ [onColumnChange],
233
+ )
234
+ : undefined;
228
235
  const [{ isDragOver }, dropConnector] = useDrop<
229
236
  QueryBuilderProjectionColumnDragSource,
230
237
  void,
@@ -237,7 +244,7 @@ export const QueryBuilderColumnBadge = observer(
237
244
  ],
238
245
  drop: (item, monitor): void => {
239
246
  if (!monitor.didDrop()) {
240
- handleDrop(item).catch(applicationStore.alertUnhandledError);
247
+ handleDrop?.(item).catch(applicationStore.alertUnhandledError);
241
248
  } // prevent drop event propagation to accomondate for nested DnD
242
249
  },
243
250
  collect: (monitor) => ({
@@ -247,47 +254,89 @@ export const QueryBuilderColumnBadge = observer(
247
254
  [applicationStore, handleDrop],
248
255
  );
249
256
 
250
- return (
257
+ const renderColumnBadgeContent = (): React.ReactNode => (
258
+ <div className="query-builder-column-badge__content">
259
+ {type && (
260
+ <div
261
+ className={clsx('query-builder-column-badge__type', {
262
+ 'query-builder-column-badge__type--class': type instanceof Class,
263
+ 'query-builder-column-badge__type--enumeration':
264
+ type instanceof Enumeration,
265
+ 'query-builder-column-badge__type--primitive':
266
+ type instanceof PrimitiveType,
267
+ })}
268
+ >
269
+ {renderPropertyTypeIcon(type)}
270
+ </div>
271
+ )}
272
+ <div
273
+ className="query-builder-column-badge__property"
274
+ title={`${colState.columnName}`}
275
+ >
276
+ {colState.columnName}
277
+ </div>
278
+ <QueryBuilderColumnInfoTooltip
279
+ columnState={colState}
280
+ placement="bottom-end"
281
+ >
282
+ <div className="query-builder-column-badge__property__info">
283
+ <InfoCircleIcon />
284
+ </div>
285
+ </QueryBuilderColumnInfoTooltip>
286
+ {removeColumn && (
287
+ <button
288
+ className="query-builder-column-badge__action"
289
+ name="Reset"
290
+ title="Reset"
291
+ onClick={removeColumn}
292
+ >
293
+ <RefreshIcon />
294
+ </button>
295
+ )}
296
+ </div>
297
+ );
298
+
299
+ return onColumnChange ? (
251
300
  <div ref={dropConnector} className="query-builder-column-badge">
252
301
  <PanelEntryDropZonePlaceholder
253
302
  isDragOver={isDragOver}
254
303
  label="Change Property"
255
304
  >
256
- <div className="query-builder-column-badge__content">
257
- {type && (
258
- <div
259
- className={clsx('query-builder-column-badge__type', {
260
- 'query-builder-column-badge__type--class':
261
- type instanceof Class,
262
- 'query-builder-column-badge__type--enumeration':
263
- type instanceof Enumeration,
264
- 'query-builder-column-badge__type--primitive':
265
- type instanceof PrimitiveType,
266
- })}
267
- >
268
- {renderPropertyTypeIcon(type)}
269
- </div>
270
- )}
271
- <div
272
- className="query-builder-column-badge__property"
273
- title={`${colState.columnName}`}
274
- >
275
- {colState.columnName}
276
- </div>
277
- <QueryBuilderColumnInfoTooltip
278
- columnState={colState}
279
- placement="bottom-end"
280
- >
281
- <div className="query-builder-column-badge__property__info">
282
- <InfoCircleIcon />
283
- </div>
284
- </QueryBuilderColumnInfoTooltip>
285
- </div>
305
+ {renderColumnBadgeContent()}
286
306
  </PanelEntryDropZonePlaceholder>
287
307
  </div>
308
+ ) : (
309
+ <div className="query-builder-column-badge">
310
+ {renderColumnBadgeContent()}
311
+ </div>
288
312
  );
289
313
  },
290
314
  );
315
+
316
+ const isProjectionColumnDragSource = (
317
+ itemToTest:
318
+ | QueryBuilderVariableDragSource
319
+ | QueryBuilderProjectionColumnDragSource,
320
+ ): itemToTest is QueryBuilderProjectionColumnDragSource =>
321
+ Object.hasOwn(itemToTest, 'columnState');
322
+
323
+ const canDropItemOntoNodeValue = (
324
+ item: QueryBuilderVariableDragSource | QueryBuilderProjectionColumnDragSource,
325
+ condition: PostFilterConditionState,
326
+ ): boolean => {
327
+ const itemParameterType = isProjectionColumnDragSource(item)
328
+ ? item.columnState.getColumnType()
329
+ : item.variable.genericType?.value.rawType;
330
+ const conditionOperator = condition.operator;
331
+ const conditionValueType = condition.leftConditionValue.getColumnType();
332
+ return (
333
+ conditionValueType !== undefined &&
334
+ !(conditionOperator instanceof QueryBuilderPostFilterOperator_In) &&
335
+ !(conditionOperator instanceof QueryBuilderPostFilterOperator_NotIn) &&
336
+ isTypeCompatibleForAssignment(itemParameterType, conditionValueType)
337
+ );
338
+ };
339
+
291
340
  const QueryBuilderPostFilterConditionEditor = observer(
292
341
  (props: {
293
342
  node: QueryBuilderPostFilterTreeConditionNodeData;
@@ -301,29 +350,29 @@ const QueryBuilderPostFilterConditionEditor = observer(
301
350
  const changeOperator = (val: QueryBuilderPostFilterOperator) => (): void =>
302
351
  node.condition.changeOperator(val);
303
352
  const rightConditionValue = node.condition.rightConditionValue;
304
- const changeColumn = async (
305
- columnState: QueryBuilderProjectionColumnState,
306
- ): Promise<void> => {
307
- const currentColState =
308
- node.condition.leftConditionValue instanceof
309
- QueryBuilderAggregateColumnState
310
- ? node.condition.leftConditionValue.projectionColumnState
311
- : node.condition.leftConditionValue;
312
- if (currentColState !== columnState) {
313
- await flowResult(node.condition.changeColumn(columnState));
314
- }
315
- };
316
353
  // Drag and Drop on filter condition value
317
354
  const handleDrop = useCallback(
318
- (item: QueryBuilderVariableDragSource): void => {
319
- const parameterType = item.variable.genericType?.value.rawType;
355
+ (
356
+ item:
357
+ | QueryBuilderVariableDragSource
358
+ | QueryBuilderProjectionColumnDragSource,
359
+ ): void => {
360
+ const parameterType = isProjectionColumnDragSource(item)
361
+ ? item.columnState.getColumnType()
362
+ : item.variable.genericType?.value.rawType;
320
363
  const conditionValueType =
321
364
  node.condition.leftConditionValue.getColumnType();
322
- if (
323
- conditionValueType &&
324
- isTypeCompatibleForAssignment(parameterType, conditionValueType)
325
- ) {
326
- node.condition.buildFromValueSpec(item.variable);
365
+ if (canDropItemOntoNodeValue(item, node.condition)) {
366
+ if (isProjectionColumnDragSource(item)) {
367
+ node.condition.setRightConditionVal(
368
+ new PostFilterTDSColumnValueConditionValueState(
369
+ node.condition,
370
+ item.columnState,
371
+ ),
372
+ );
373
+ } else {
374
+ node.condition.buildFromValueSpec(item.variable);
375
+ }
327
376
  } else {
328
377
  applicationStore.notificationService.notifyWarning(
329
378
  `Incompatible parameter type ${parameterType?.name}. ${parameterType?.name} is not compatible with type ${conditionValueType?.name}.`,
@@ -338,18 +387,31 @@ const QueryBuilderPostFilterConditionEditor = observer(
338
387
  { isFilterValueDragOver: boolean }
339
388
  >(
340
389
  () => ({
341
- accept: [QUERY_BUILDER_VARIABLE_DND_TYPE],
390
+ accept: [
391
+ QUERY_BUILDER_VARIABLE_DND_TYPE,
392
+ QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
393
+ ],
394
+ canDrop: (item): boolean =>
395
+ canDropItemOntoNodeValue(item, node.condition),
342
396
  drop: (item, monitor): void => {
343
397
  if (!monitor.didDrop()) {
344
398
  handleDrop(item);
345
399
  } // prevent drop event propagation to accomondate for nested DnD
346
400
  },
347
401
  collect: (monitor) => ({
348
- isFilterValueDragOver: monitor.isOver({ shallow: true }),
402
+ isFilterValueDragOver:
403
+ monitor.isOver({ shallow: true }) && monitor.canDrop(),
349
404
  }),
350
405
  }),
351
406
  [handleDrop],
352
407
  );
408
+ const { isFilterValueDroppable } = useDragLayer((monitor) => ({
409
+ isFilterValueDroppable:
410
+ monitor.isDragging() &&
411
+ (monitor.getItemType() === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
412
+ monitor.getItemType() === QUERY_BUILDER_VARIABLE_DND_TYPE) &&
413
+ canDropItemOntoNodeValue(monitor.getItem(), node.condition),
414
+ }));
353
415
  const resetNode = (): void => {
354
416
  node.condition.buildFromValueSpec(
355
417
  node.condition.operator.getDefaultFilterConditionValue(node.condition),
@@ -375,13 +437,11 @@ const QueryBuilderPostFilterConditionEditor = observer(
375
437
  reloadValues: debouncedTypeaheadSearch,
376
438
  cleanUpReloadValues,
377
439
  };
378
-
379
- const { isDroppable } = useDragLayer((monitor) => ({
380
- isDroppable:
381
- monitor.isDragging() &&
382
- (monitor.getItemType() === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
383
- monitor.getItemType() === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE),
384
- }));
440
+ const removeTDSColumnValue = (): void => {
441
+ node.condition.buildFromValueSpec(
442
+ node.condition.operator.getDefaultFilterConditionValue(node.condition),
443
+ );
444
+ };
385
445
 
386
446
  const renderRightVal = (): React.ReactNode => {
387
447
  if (
@@ -395,6 +455,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
395
455
  >
396
456
  <PanelEntryDropZonePlaceholder
397
457
  isDragOver={isFilterValueDragOver}
458
+ isDroppable={isFilterValueDroppable}
398
459
  label="Change Filter Value"
399
460
  >
400
461
  <BasicValueSpecificationEditor
@@ -432,12 +493,16 @@ const QueryBuilderPostFilterConditionEditor = observer(
432
493
  >
433
494
  <PanelEntryDropZonePlaceholder
434
495
  isDragOver={isFilterValueDragOver}
496
+ isDroppable={isFilterValueDroppable}
435
497
  label="Change Filter Value"
436
498
  >
437
499
  <div className="query-builder-post-filter-tree__condition-node__property">
438
500
  <QueryBuilderColumnBadge
439
501
  colState={rightConditionValue.tdsColumn}
440
- onColumnChange={changeRightCol}
502
+ onColumnChange={
503
+ isFilterValueDroppable ? changeRightCol : undefined
504
+ }
505
+ removeColumn={removeTDSColumnValue}
441
506
  />
442
507
  </div>
443
508
  </PanelEntryDropZonePlaceholder>
@@ -450,15 +515,14 @@ const QueryBuilderPostFilterConditionEditor = observer(
450
515
  return (
451
516
  <div className="query-builder-post-filter-tree__node__label__content dnd__entry__container">
452
517
  <PanelEntryDropZonePlaceholder
453
- isDragOver={isDragOver}
454
- isDroppable={isDroppable}
455
- label="Add New Logical Group"
518
+ isDragOver={isDragOver && !isFilterValueDragOver}
519
+ alwaysShowChildren={true}
520
+ className="query-builder-post-filter-tree__node__drop-zone-placeholder"
456
521
  >
457
522
  <div className="query-builder-post-filter-tree__condition-node">
458
523
  <div className="query-builder-post-filter-tree__condition-node__property">
459
524
  <QueryBuilderColumnBadge
460
525
  colState={node.condition.leftConditionValue}
461
- onColumnChange={changeColumn}
462
526
  />
463
527
  </div>
464
528
  <DropdownMenu
@@ -631,10 +695,10 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
631
695
  },
632
696
  [applicationStore, postFilterState, node],
633
697
  );
634
- const [{ isDragOver }, dropConnector] = useDrop<
698
+ const [{ isDragOver, deepIsDragOver }, dropConnector] = useDrop<
635
699
  QueryBuilderPostFilterConditionDragSource,
636
700
  void,
637
- { isDragOver: boolean }
701
+ { isDragOver: boolean; deepIsDragOver: boolean }
638
702
  >(
639
703
  () => ({
640
704
  accept: [
@@ -649,6 +713,7 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
649
713
  },
650
714
  collect: (monitor) => ({
651
715
  isDragOver: monitor.isOver({ shallow: true }),
716
+ deepIsDragOver: monitor.isOver({ shallow: false }),
652
717
  }),
653
718
  }),
654
719
  [handleDrop],
@@ -746,7 +811,7 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
746
811
  {node instanceof QueryBuilderPostFilterTreeConditionNodeData && (
747
812
  <QueryBuilderPostFilterConditionEditor
748
813
  node={node}
749
- isDragOver={isDragOver}
814
+ isDragOver={deepIsDragOver}
750
815
  />
751
816
  )}
752
817
  {node instanceof
@@ -1389,12 +1389,20 @@ export const QueryBuilderTDSPanel = observer(
1389
1389
  <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1390
1390
  (
1391
1391
  {getNameOfValueSpecification(
1392
- tdsState.queryBuilderState.milestoningState.startDate,
1392
+ tdsState.queryBuilderState.milestoningState.getMilestoningParameterValue(
1393
+ tdsState.queryBuilderState.milestoningState
1394
+ .startDate,
1395
+ ) ??
1396
+ tdsState.queryBuilderState.milestoningState
1397
+ .startDate,
1393
1398
  tdsState.queryBuilderState,
1394
1399
  )}{' '}
1395
1400
  -{' '}
1396
1401
  {getNameOfValueSpecification(
1397
- tdsState.queryBuilderState.milestoningState.endDate,
1402
+ tdsState.queryBuilderState.milestoningState.getMilestoningParameterValue(
1403
+ tdsState.queryBuilderState.milestoningState.endDate,
1404
+ ) ??
1405
+ tdsState.queryBuilderState.milestoningState.endDate,
1398
1406
  tdsState.queryBuilderState,
1399
1407
  )}
1400
1408
  )
@@ -1413,8 +1421,12 @@ export const QueryBuilderTDSPanel = observer(
1413
1421
  >
1414
1422
  <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1415
1423
  {getNameOfValueSpecification(
1416
- tdsState.queryBuilderState.milestoningState
1417
- .businessDate,
1424
+ tdsState.queryBuilderState.milestoningState.getMilestoningParameterValue(
1425
+ tdsState.queryBuilderState.milestoningState
1426
+ .businessDate,
1427
+ ) ??
1428
+ tdsState.queryBuilderState.milestoningState
1429
+ .businessDate,
1418
1430
  tdsState.queryBuilderState,
1419
1431
  )}
1420
1432
  </div>
@@ -1432,8 +1444,12 @@ export const QueryBuilderTDSPanel = observer(
1432
1444
  >
1433
1445
  <div className="query-builder__projection__result-modifier-prompt__header__label__title">
1434
1446
  {getNameOfValueSpecification(
1435
- tdsState.queryBuilderState.milestoningState
1436
- .processingDate,
1447
+ tdsState.queryBuilderState.milestoningState.getMilestoningParameterValue(
1448
+ tdsState.queryBuilderState.milestoningState
1449
+ .processingDate,
1450
+ ) ??
1451
+ tdsState.queryBuilderState.milestoningState
1452
+ .processingDate,
1437
1453
  tdsState.queryBuilderState,
1438
1454
  )}
1439
1455
  </div>
@@ -204,7 +204,15 @@ export const QueryBuilderResultPanel = observer(
204
204
  const runQuery = (): void => {
205
205
  resultState.setSelectedCells([]);
206
206
  resultState.pressedRunQuery.inProgress();
207
- if (queryParametersState.parameterStates.length) {
207
+ if (
208
+ queryParametersState.parameterStates.length &&
209
+ queryParametersState.parameterStates.find(
210
+ (param) =>
211
+ !queryBuilderState.milestoningState.isMilestoningParameter(
212
+ param.parameter,
213
+ ),
214
+ )
215
+ ) {
208
216
  queryParametersState.parameterValuesEditorState.open(
209
217
  (): Promise<void> =>
210
218
  flowResult(resultState.runQuery()).catch(
@@ -149,6 +149,18 @@ export const VariableViewer = observer(
149
149
  const variableTypeName =
150
150
  variable.genericType?.value.rawType.name ??
151
151
  (isConstant ? CALCULATED : undefined);
152
+ const isMilestoningParameter =
153
+ queryBuilderState.milestoningState.isMilestoningParameter(variable);
154
+ const milestoningParameterValue =
155
+ queryBuilderState.milestoningState.getMilestoningParameterValue(variable);
156
+ const milestoningParameterValueString = isMilestoningParameter
157
+ ? milestoningParameterValue
158
+ ? getNameOfValueSpecification(
159
+ milestoningParameterValue,
160
+ queryBuilderState,
161
+ )
162
+ : undefined
163
+ : undefined;
152
164
  const deleteDisabled = isReadOnly || isVariableUsed;
153
165
  const deleteTitle = isVariableUsed ? 'Used in query' : 'Remove';
154
166
  const editVariable = (): void => {
@@ -227,6 +239,16 @@ export const VariableViewer = observer(
227
239
  <div className="query-builder__variables__variable__type__label">
228
240
  {variableTypeName ?? 'unknown'}
229
241
  </div>
242
+ {isMilestoningParameter && (
243
+ <>
244
+ <div className="query-builder__variables__variable__type__label query-builder__variables__variable__type__label--milestoning">
245
+ milestoning
246
+ </div>
247
+ <div className="query-builder__constants__value">
248
+ {milestoningParameterValueString}
249
+ </div>
250
+ </>
251
+ )}
230
252
  </div>
231
253
  )}
232
254
  </div>
@@ -240,7 +240,7 @@ export const isTypeCompatibleForAssignment = (
240
240
  // Pure function used for the operation
241
241
  // e.g. LHS(DateTime) = RHS(Date) -> we use isOnDay() instead of is()
242
242
  DATE_PRIMITIVE_TYPES.includes(type.path) ||
243
- type === assignmentType ||
243
+ type.path === assignmentType.path ||
244
244
  isSuperType(assignmentType, type))
245
245
  );
246
246
  };
@@ -481,6 +481,33 @@ export class QueryBuilderMilestoningState implements Hashable {
481
481
  return milestoningParameter;
482
482
  }
483
483
 
484
+ updateMilestoningParameterValue(
485
+ parameter: VariableExpression,
486
+ value: ValueSpecification | undefined,
487
+ ): void {
488
+ const variableState =
489
+ this.queryBuilderState.parametersState.parameterStates.find(
490
+ (param) => param.parameter.name === parameter.name,
491
+ );
492
+ if (variableState) {
493
+ variableState.setValue(value);
494
+ }
495
+ }
496
+
497
+ getMilestoningParameterValue(
498
+ milestoningParameter: ValueSpecification,
499
+ ): ValueSpecification | undefined {
500
+ let value: ValueSpecification | undefined = milestoningParameter;
501
+ if (milestoningParameter instanceof VariableExpression) {
502
+ const paramState =
503
+ this.queryBuilderState.parametersState.parameterStates.find(
504
+ (param) => param.parameter.name === milestoningParameter.name,
505
+ );
506
+ value = paramState?.value;
507
+ }
508
+ return value;
509
+ }
510
+
484
511
  isVariableUsed(variable: VariableExpression): boolean {
485
512
  const usedInBusiness = this.businessDate
486
513
  ? isValueExpressionReferencedInValue(variable, this.businessDate)
@@ -491,6 +518,33 @@ export class QueryBuilderMilestoningState implements Hashable {
491
518
  return usedInBusiness || usedInProcessingDate;
492
519
  }
493
520
 
521
+ isMilestoningParameter(parameter: VariableExpression): boolean {
522
+ let isMilestoningParameter = false;
523
+ if (this.businessDate instanceof VariableExpression) {
524
+ isMilestoningParameter =
525
+ parameter.name ===
526
+ guaranteeType(this.businessDate, VariableExpression).name;
527
+ }
528
+ if (this.processingDate instanceof VariableExpression) {
529
+ isMilestoningParameter =
530
+ isMilestoningParameter ||
531
+ parameter.name ===
532
+ guaranteeType(this.processingDate, VariableExpression).name;
533
+ }
534
+ if (this.startDate instanceof VariableExpression) {
535
+ isMilestoningParameter =
536
+ isMilestoningParameter ||
537
+ parameter.name ===
538
+ guaranteeType(this.startDate, VariableExpression).name;
539
+ }
540
+ if (this.endDate instanceof VariableExpression) {
541
+ isMilestoningParameter =
542
+ isMilestoningParameter ||
543
+ parameter.name === guaranteeType(this.endDate, VariableExpression).name;
544
+ }
545
+ return isMilestoningParameter;
546
+ }
547
+
494
548
  get hashCode(): string {
495
549
  return hashArray([
496
550
  QUERY_BUILDER_STATE_HASH_STRUCTURE.MILESTONING_STATE,
@@ -46,6 +46,7 @@ import {
46
46
  import {
47
47
  Randomizer,
48
48
  UnsupportedOperationError,
49
+ deepClone,
49
50
  returnUndefOnError,
50
51
  } from '@finos/legend-shared';
51
52
  import { generateDefaultValueForPrimitiveType } from '../QueryBuilderValueSpecificationHelper.js';
@@ -84,6 +85,16 @@ export const buildPrimitiveInstanceValue = (
84
85
  return instance;
85
86
  };
86
87
 
88
+ export const cloneValueSpecification = (
89
+ valueSpecification: ValueSpecification,
90
+ observerContext: ObserverContext,
91
+ ): ValueSpecification => {
92
+ const copy = deepClone(valueSpecification);
93
+ copy.genericType = valueSpecification.genericType;
94
+ copy.multiplicity = valueSpecification.multiplicity;
95
+ return copy;
96
+ };
97
+
87
98
  export const createMockPrimitiveValueSpecification = (
88
99
  primitiveType: PrimitiveType,
89
100
  graph: PureModel,