@finos/legend-query-builder 4.5.1 → 4.7.0

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 (57) hide show
  1. package/lib/__lib__/QueryBuilderTesting.d.ts +1 -0
  2. package/lib/__lib__/QueryBuilderTesting.d.ts.map +1 -1
  3. package/lib/__lib__/QueryBuilderTesting.js +1 -0
  4. package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
  5. package/lib/components/QueryBuilderConstantExpressionPanel.d.ts.map +1 -1
  6. package/lib/components/QueryBuilderConstantExpressionPanel.js +46 -9
  7. package/lib/components/QueryBuilderConstantExpressionPanel.js.map +1 -1
  8. package/lib/components/QueryBuilderParametersPanel.d.ts.map +1 -1
  9. package/lib/components/QueryBuilderParametersPanel.js.map +1 -1
  10. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  11. package/lib/components/QueryBuilderResultPanel.js +1 -1
  12. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  13. package/lib/components/shared/BasicValueSpecificationEditor.d.ts.map +1 -1
  14. package/lib/components/shared/BasicValueSpecificationEditor.js +2 -2
  15. package/lib/components/shared/BasicValueSpecificationEditor.js.map +1 -1
  16. package/lib/components/shared/CustomDatePicker.d.ts.map +1 -1
  17. package/lib/components/shared/CustomDatePicker.js +6 -2
  18. package/lib/components/shared/CustomDatePicker.js.map +1 -1
  19. package/lib/components/shared/LambdaEditor.d.ts +11 -0
  20. package/lib/components/shared/LambdaEditor.d.ts.map +1 -1
  21. package/lib/components/shared/LambdaEditor.js +3 -3
  22. package/lib/components/shared/LambdaEditor.js.map +1 -1
  23. package/lib/components/shared/QueryBuilderVariableSelector.d.ts +9 -2
  24. package/lib/components/shared/QueryBuilderVariableSelector.d.ts.map +1 -1
  25. package/lib/components/shared/QueryBuilderVariableSelector.js +38 -19
  26. package/lib/components/shared/QueryBuilderVariableSelector.js.map +1 -1
  27. package/lib/index.css +1 -17
  28. package/lib/index.css.map +1 -1
  29. package/lib/package.json +1 -1
  30. package/lib/stores/QueryBuilderConfig.d.ts +2 -1
  31. package/lib/stores/QueryBuilderConfig.d.ts.map +1 -1
  32. package/lib/stores/QueryBuilderConfig.js +1 -0
  33. package/lib/stores/QueryBuilderConfig.js.map +1 -1
  34. package/lib/stores/QueryBuilderConstantsState.d.ts +26 -2
  35. package/lib/stores/QueryBuilderConstantsState.d.ts.map +1 -1
  36. package/lib/stores/QueryBuilderConstantsState.js +107 -5
  37. package/lib/stores/QueryBuilderConstantsState.js.map +1 -1
  38. package/lib/stores/QueryBuilderStateBuilder.d.ts +1 -1
  39. package/lib/stores/QueryBuilderStateBuilder.d.ts.map +1 -1
  40. package/lib/stores/QueryBuilderStateBuilder.js +9 -4
  41. package/lib/stores/QueryBuilderStateBuilder.js.map +1 -1
  42. package/lib/stores/QueryBuilderValueSpecificationBuilder.d.ts.map +1 -1
  43. package/lib/stores/QueryBuilderValueSpecificationBuilder.js +14 -3
  44. package/lib/stores/QueryBuilderValueSpecificationBuilder.js.map +1 -1
  45. package/package.json +5 -5
  46. package/src/__lib__/QueryBuilderTesting.ts +1 -0
  47. package/src/components/QueryBuilderConstantExpressionPanel.tsx +95 -13
  48. package/src/components/QueryBuilderParametersPanel.tsx +0 -1
  49. package/src/components/QueryBuilderResultPanel.tsx +4 -1
  50. package/src/components/shared/BasicValueSpecificationEditor.tsx +4 -7
  51. package/src/components/shared/CustomDatePicker.tsx +6 -7
  52. package/src/components/shared/LambdaEditor.tsx +4 -2
  53. package/src/components/shared/QueryBuilderVariableSelector.tsx +192 -83
  54. package/src/stores/QueryBuilderConfig.ts +1 -0
  55. package/src/stores/QueryBuilderConstantsState.ts +175 -5
  56. package/src/stores/QueryBuilderStateBuilder.ts +20 -8
  57. package/src/stores/QueryBuilderValueSpecificationBuilder.ts +31 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-query-builder",
3
- "version": "4.5.1",
3
+ "version": "4.7.0",
4
4
  "description": "Legend query builder core",
5
5
  "keywords": [
6
6
  "legend",
@@ -42,10 +42,10 @@
42
42
  "test:watch": "jest --watch"
43
43
  },
44
44
  "dependencies": {
45
- "@finos/legend-application": "15.0.40",
46
- "@finos/legend-art": "7.0.40",
47
- "@finos/legend-graph": "31.2.0",
48
- "@finos/legend-lego": "1.1.28",
45
+ "@finos/legend-application": "15.0.41",
46
+ "@finos/legend-art": "7.0.41",
47
+ "@finos/legend-graph": "31.2.2",
48
+ "@finos/legend-lego": "1.1.30",
49
49
  "@finos/legend-server-depot": "6.0.29",
50
50
  "@finos/legend-shared": "10.0.25",
51
51
  "@finos/legend-storage": "3.0.75",
@@ -27,6 +27,7 @@ export enum QUERY_BUILDER_TEST_ID {
27
27
  QUERY_BUILDER_EXPLORER = 'query__builder__explorer',
28
28
  QUERY_BUILDER_PROPERTY_SEARCH_PANEL = 'query__builder__property__search__panel',
29
29
  QUERY_BUILDER_RESULT_PANEL = 'query__builder__result__panel',
30
+ QUERY_BUILDER_RESULT_ANALYTICS = 'query__builder__result__analytics',
30
31
  QUERY_BUILDER_PARAMETERS = 'query-builder__parameters',
31
32
  QUERY_BUILDER_CONSTANTS = 'query-builder__constants',
32
33
  }
@@ -21,6 +21,7 @@ import {
21
21
  } from '@finos/legend-lego/graph-editor';
22
22
  import {
23
23
  BlankPanelPlaceholder,
24
+ clsx,
24
25
  CustomSelectorInput,
25
26
  Dialog,
26
27
  InfoCircleIcon,
@@ -41,23 +42,31 @@ import {
41
42
  Multiplicity,
42
43
  isValidIdentifier,
43
44
  } from '@finos/legend-graph';
44
- import { generateEnumerableNameFromToken } from '@finos/legend-shared';
45
+ import {
46
+ debounce,
47
+ generateEnumerableNameFromToken,
48
+ } from '@finos/legend-shared';
45
49
  import { observer } from 'mobx-react-lite';
46
50
  import { DEFAULT_CONSTANT_VARIABLE_NAME } from '../stores/QueryBuilderConfig.js';
47
51
  import type { QueryBuilderState } from '../stores/QueryBuilderState.js';
48
- import { QueryBuilderConstantExpressionState } from '../stores/QueryBuilderConstantsState.js';
52
+ import {
53
+ type QueryBuilderConstantExpressionState,
54
+ QueryBuilderSimpleConstantExpressionState,
55
+ QueryBuilderCalculatedConstantExpressionState,
56
+ } from '../stores/QueryBuilderConstantsState.js';
49
57
  import { buildDefaultInstanceValue } from '../stores/shared/ValueSpecificationEditorHelper.js';
50
58
  import { BasicValueSpecificationEditor } from './shared/BasicValueSpecificationEditor.js';
51
- import { VariableViewer } from './shared/QueryBuilderVariableSelector.js';
52
59
  import { QUERY_BUILDER_TEST_ID } from '../__lib__/QueryBuilderTesting.js';
53
60
  import { QUERY_BUILDER_DOCUMENTATION_KEY } from '../__lib__/QueryBuilderDocumentation.js';
54
- import { useState } from 'react';
61
+ import React, { useMemo, useState } from 'react';
55
62
  import { variableExpression_setName } from '../stores/shared/ValueSpecificationModifierHelper.js';
63
+ import { LambdaEditor_PopUp } from './shared/LambdaEditor.js';
64
+ import { VariableViewer } from './shared/QueryBuilderVariableSelector.js';
56
65
 
57
66
  // NOTE: We currently only allow constant variables for primitive types of multiplicity ONE.
58
67
  // This is why we don't show multiplicity in the editor.
59
- const QueryBuilderConstantExpressionEditor = observer(
60
- (props: { constantState: QueryBuilderConstantExpressionState }) => {
68
+ const QueryBuilderSimpleConstantExpressionEditor = observer(
69
+ (props: { constantState: QueryBuilderSimpleConstantExpressionState }) => {
61
70
  const { constantState } = props;
62
71
  const queryBuilderState = constantState.queryBuilderState;
63
72
  const applicationStore = queryBuilderState.applicationStore;
@@ -205,6 +214,35 @@ const QueryBuilderConstantExpressionEditor = observer(
205
214
  },
206
215
  );
207
216
 
217
+ const QuerryBuilderCalculatedConstantExpressionEditor = observer(
218
+ (props: { constantState: QueryBuilderCalculatedConstantExpressionState }) => {
219
+ const { constantState } = props;
220
+ const queryBuilderState = constantState.queryBuilderState;
221
+ const lambdaState = constantState.lambdaState;
222
+ const closePopUp = (): void =>
223
+ queryBuilderState.constantState.setSelectedConstant(undefined);
224
+ const debouncedTransformStringToLambda = useMemo(
225
+ () =>
226
+ debounce(() => lambdaState.convertLambdaGrammarStringToObject(), 1000),
227
+ [lambdaState],
228
+ );
229
+ const canDrop = true;
230
+ return (
231
+ <>
232
+ <div className="lambda-editor" />
233
+ <LambdaEditor_PopUp
234
+ title={`Edit Constant ${constantState.variable.name}`}
235
+ className={clsx({ 'lambda-editor--dnd-match': canDrop })}
236
+ disabled={false}
237
+ lambdaEditorState={lambdaState}
238
+ transformStringToLambda={debouncedTransformStringToLambda}
239
+ onClose={closePopUp}
240
+ />
241
+ </>
242
+ );
243
+ },
244
+ );
245
+
208
246
  export const QueryBuilderConstantExpressionPanel = observer(
209
247
  (props: { queryBuilderState: QueryBuilderState }) => {
210
248
  const { queryBuilderState } = props;
@@ -232,7 +270,7 @@ export const QueryBuilderConstantExpressionPanel = observer(
232
270
  Multiplicity.ONE,
233
271
  );
234
272
  variableEx.genericType = defaultVal.genericType;
235
- const constState = new QueryBuilderConstantExpressionState(
273
+ const constState = new QueryBuilderSimpleConstantExpressionState(
236
274
  queryBuilderState,
237
275
  variableEx,
238
276
  defaultVal,
@@ -241,6 +279,46 @@ export const QueryBuilderConstantExpressionPanel = observer(
241
279
  }
242
280
  };
243
281
 
282
+ const renderConstantModal = (
283
+ val: QueryBuilderConstantExpressionState,
284
+ ): React.ReactNode => {
285
+ if (val instanceof QueryBuilderSimpleConstantExpressionState) {
286
+ return (
287
+ <QueryBuilderSimpleConstantExpressionEditor constantState={val} />
288
+ );
289
+ } else if (val instanceof QueryBuilderCalculatedConstantExpressionState) {
290
+ return (
291
+ <QuerryBuilderCalculatedConstantExpressionEditor
292
+ constantState={val}
293
+ />
294
+ );
295
+ }
296
+ return null;
297
+ };
298
+ const getExtraContextMenu = (
299
+ val: QueryBuilderConstantExpressionState,
300
+ ):
301
+ | {
302
+ key: string;
303
+ label: string;
304
+ handler: () => void;
305
+ }[]
306
+ | undefined => {
307
+ if (val instanceof QueryBuilderSimpleConstantExpressionState) {
308
+ return [
309
+ {
310
+ key: 'convert-to-derivation',
311
+ label: 'Convert To Derivation',
312
+ handler: () =>
313
+ constantState.queryBuilderState.constantState.convertToCalculated(
314
+ val,
315
+ ),
316
+ },
317
+ ];
318
+ }
319
+ return undefined;
320
+ };
321
+
244
322
  return (
245
323
  <div
246
324
  data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_CONSTANTS}
@@ -278,13 +356,20 @@ export const QueryBuilderConstantExpressionPanel = observer(
278
356
  key={constState.uuid}
279
357
  queryBuilderState={queryBuilderState}
280
358
  variable={constState.variable}
281
- constantValue={constState.value}
359
+ value={{
360
+ val:
361
+ constState instanceof
362
+ QueryBuilderSimpleConstantExpressionState
363
+ ? constState.value
364
+ : undefined,
365
+ }}
282
366
  actions={{
283
367
  editVariable: () =>
284
368
  constantState.setSelectedConstant(constState),
285
369
  deleteVariable: () =>
286
370
  constantState.removeConstant(constState),
287
371
  }}
372
+ extraContextMenuActions={getExtraContextMenu(constState)}
288
373
  isReadOnly={isReadOnly}
289
374
  />
290
375
  ))}
@@ -300,11 +385,8 @@ export const QueryBuilderConstantExpressionPanel = observer(
300
385
  )}
301
386
  </>
302
387
  </div>
303
- {constantState.selectedConstant && (
304
- <QueryBuilderConstantExpressionEditor
305
- constantState={constantState.selectedConstant}
306
- />
307
- )}
388
+ {constantState.selectedConstant &&
389
+ renderConstantModal(constantState.selectedConstant)}
308
390
  </div>
309
391
  );
310
392
  },
@@ -266,7 +266,6 @@ export const QueryBuilderParametersPanel = observer(
266
266
  parmaterState.mockParameterValue();
267
267
  }
268
268
  };
269
-
270
269
  return (
271
270
  <div
272
271
  data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_PARAMETERS}
@@ -1069,7 +1069,10 @@ export const QueryBuilderResultPanel = observer(
1069
1069
  </div>
1070
1070
  )}
1071
1071
 
1072
- <div className="query-builder__result__analytics">
1072
+ <div
1073
+ data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_ANALYTICS}
1074
+ className="query-builder__result__analytics"
1075
+ >
1073
1076
  {resultDescription ?? ''}
1074
1077
  </div>
1075
1078
  {executionResult && resultState.checkForStaleResults && (
@@ -121,7 +121,7 @@ export const VariableInfoTooltip: React.FC<{
121
121
  Type
122
122
  </div>
123
123
  <div className="value-spec-paramater__tooltip__item__value">
124
- {type?.name ?? ''}
124
+ {type?.name ?? '(unknown)'}
125
125
  </div>
126
126
  </div>
127
127
  <div className="value-spec-paramater__tooltip__item">
@@ -871,12 +871,9 @@ const CollectionValueInstanceValueEditor = observer(
871
871
  onClick={enableEdit}
872
872
  title="Click to edit"
873
873
  >
874
- <input
875
- className="value-spec-editor__list-editor__preview"
876
- spellCheck={false}
877
- value={previewText}
878
- disabled={true}
879
- />
874
+ <div className="value-spec-editor__list-editor__preview">
875
+ {previewText}
876
+ </div>
880
877
  <button className="value-spec-editor__list-editor__edit-icon">
881
878
  <PencilIcon />
882
879
  </button>
@@ -840,22 +840,21 @@ const AbsoluteTimeValueSpecificationEditor: React.FC<{
840
840
  const updateAbsoluteTimeValue: React.ChangeEventHandler<HTMLInputElement> = (
841
841
  event,
842
842
  ) => {
843
+ //
844
+ const value = new Date(event.target.value).getUTCSeconds()
845
+ ? event.target.value
846
+ : `${event.target.value}:00`;
843
847
  if (valueSpecification instanceof SimpleFunctionExpression) {
844
848
  setValueSpecification(
845
849
  buildPrimitiveInstanceValue(
846
850
  graph,
847
851
  PRIMITIVE_TYPE.DATETIME,
848
- event.target.value,
852
+ value,
849
853
  observerContext,
850
854
  ),
851
855
  );
852
856
  } else {
853
- instanceValue_setValue(
854
- valueSpecification,
855
- event.target.value,
856
- 0,
857
- observerContext,
858
- );
857
+ instanceValue_setValue(valueSpecification, value, 0, observerContext);
859
858
  if (
860
859
  valueSpecification.genericType.value.rawType.path !==
861
860
  PRIMITIVE_TYPE.DATETIME
@@ -419,8 +419,9 @@ const LambdaEditor_Inner = observer(
419
419
  },
420
420
  );
421
421
 
422
- const LambdaEditor_PopUp = observer(
422
+ export const LambdaEditor_PopUp = observer(
423
423
  (props: {
424
+ title?: string | undefined;
424
425
  className?: string | undefined;
425
426
  disabled: boolean;
426
427
  lambdaEditorState: LambdaEditorState;
@@ -432,6 +433,7 @@ const LambdaEditor_PopUp = observer(
432
433
  disabled,
433
434
  lambdaEditorState,
434
435
  transformStringToLambda,
436
+ title,
435
437
  onClose,
436
438
  } = props;
437
439
  const applicationStore = useApplicationStore();
@@ -607,7 +609,7 @@ const LambdaEditor_PopUp = observer(
607
609
  )}
608
610
  >
609
611
  <ModalHeader>
610
- <ModalTitle title="Edit Lambda" />
612
+ <ModalTitle title={title ?? 'Edit Lambda'} />
611
613
  {lambdaEditorState.parserError && (
612
614
  <div className="modal__title__error-badge">
613
615
  Failed to parse lambda
@@ -15,18 +15,23 @@
15
15
  */
16
16
 
17
17
  import {
18
+ CalculatorIcon,
19
+ ContextMenu,
18
20
  DollarIcon,
19
21
  DragPreviewLayer,
20
22
  InfoCircleIcon,
23
+ MenuContent,
24
+ MenuContentItem,
21
25
  PanelFormListItems,
22
26
  PencilIcon,
23
27
  TimesIcon,
28
+ clsx,
24
29
  useDragPreviewLayer,
25
30
  } from '@finos/legend-art';
26
31
  import {
27
- SimpleFunctionExpression,
28
- type ValueSpecification,
29
32
  type VariableExpression,
33
+ type ValueSpecification,
34
+ SimpleFunctionExpression,
30
35
  } from '@finos/legend-graph';
31
36
  import { observer } from 'mobx-react-lite';
32
37
  import { useDrag } from 'react-dnd';
@@ -38,41 +43,112 @@ import {
38
43
  VariableInfoTooltip,
39
44
  } from './BasicValueSpecificationEditor.js';
40
45
  import { buildDatePickerOption } from './CustomDatePicker.js';
46
+ import { QueryBuilderSimpleConstantExpressionState } from '../../stores/QueryBuilderConstantsState.js';
47
+ import { forwardRef, useState } from 'react';
41
48
 
49
+ const CALCULATED = '(calculated)';
50
+
51
+ const getNameOfValue = (
52
+ value: ValueSpecification,
53
+ queryBuilderState: QueryBuilderState,
54
+ ): string | undefined => {
55
+ if (value instanceof SimpleFunctionExpression) {
56
+ const possibleDateLabel = buildDatePickerOption(
57
+ value,
58
+ queryBuilderState.applicationStore,
59
+ ).label;
60
+ if (possibleDateLabel) {
61
+ return possibleDateLabel;
62
+ }
63
+ }
64
+ return getValueSpecificationStringValue(value);
65
+ };
66
+
67
+ const QueryBuilderVariableContextMenu = observer(
68
+ forwardRef<
69
+ HTMLDivElement,
70
+ {
71
+ variable: VariableExpression;
72
+ variableInUse: boolean;
73
+ actions?:
74
+ | {
75
+ editVariable: () => void;
76
+ deleteVariable: () => void;
77
+ }
78
+ | undefined;
79
+ extraContextMenuActions?:
80
+ | {
81
+ key: string;
82
+ label: string;
83
+ handler: () => void;
84
+ }[]
85
+ | undefined;
86
+ }
87
+ >(function QueryBuilderVariableContextMenu(props, ref) {
88
+ const { actions, extraContextMenuActions, variableInUse } = props;
89
+ return (
90
+ <MenuContent ref={ref}>
91
+ {extraContextMenuActions?.map((action) => (
92
+ <MenuContentItem onClick={action.handler} key={action.key}>
93
+ {action.label}
94
+ </MenuContentItem>
95
+ ))}
96
+ {actions?.editVariable && (
97
+ <MenuContentItem onClick={actions.editVariable}>Edit</MenuContentItem>
98
+ )}
99
+ {actions?.deleteVariable && (
100
+ <MenuContentItem
101
+ disabled={variableInUse}
102
+ onClick={actions.deleteVariable}
103
+ >
104
+ Remove
105
+ </MenuContentItem>
106
+ )}
107
+ </MenuContent>
108
+ );
109
+ }),
110
+ );
42
111
  export const VariableViewer = observer(
43
112
  (props: {
44
113
  variable: VariableExpression;
45
114
  queryBuilderState: QueryBuilderState;
46
115
  isReadOnly: boolean;
47
- constantValue?: ValueSpecification | undefined;
116
+ value?: {
117
+ val: ValueSpecification | undefined;
118
+ };
48
119
  actions?: {
49
120
  editVariable: () => void;
50
121
  deleteVariable: () => void;
51
122
  };
123
+ extraContextMenuActions?:
124
+ | {
125
+ key: string;
126
+ label: string;
127
+ handler: () => void;
128
+ }[]
129
+ | undefined;
52
130
  }) => {
53
- const { variable, constantValue, actions, isReadOnly, queryBuilderState } =
54
- props;
55
-
56
- const getNameOfValue = (value: ValueSpecification): string | undefined => {
57
- if (value instanceof SimpleFunctionExpression) {
58
- const possibleDateLabel = buildDatePickerOption(
59
- value,
60
- queryBuilderState.applicationStore,
61
- ).label;
62
- if (possibleDateLabel) {
63
- return possibleDateLabel;
64
- }
65
- }
66
- return getValueSpecificationStringValue(value);
67
- };
68
-
69
- const valueString = constantValue
70
- ? getNameOfValue(constantValue)
131
+ const {
132
+ variable,
133
+ value,
134
+ actions,
135
+ isReadOnly,
136
+ queryBuilderState,
137
+ extraContextMenuActions,
138
+ } = props;
139
+ const isVariableUsed = queryBuilderState.isVariableUsed(variable);
140
+ const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] =
141
+ useState(false);
142
+ const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true);
143
+ const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false);
144
+ const isConstant = Boolean(value);
145
+ const constantValueString = value?.val
146
+ ? getNameOfValue(value.val, queryBuilderState)
71
147
  : undefined;
72
148
  const name = variable.name;
73
- const variableType = variable.genericType?.value.rawType;
74
- const typeName = variableType?.name;
75
- const isVariableUsed = queryBuilderState.isVariableUsed(variable);
149
+ const variableTypeName =
150
+ variable.genericType?.value.rawType.name ??
151
+ (isConstant ? CALCULATED : undefined);
76
152
  const deleteDisabled = isReadOnly || isVariableUsed;
77
153
  const deleteTitle = isVariableUsed ? 'Used in query' : 'Remove';
78
154
  const editVariable = (): void => {
@@ -81,6 +157,7 @@ export const VariableViewer = observer(
81
157
  const deleteVariable = (): void => {
82
158
  actions?.deleteVariable();
83
159
  };
160
+
84
161
  const [, dragConnector, dragPreviewConnector] = useDrag(
85
162
  () => ({
86
163
  type: QUERY_BUILDER_VARIABLE_DND_TYPE,
@@ -92,69 +169,96 @@ export const VariableViewer = observer(
92
169
 
93
170
  return (
94
171
  <div className="query-builder__variables__variable" ref={dragConnector}>
95
- <DragPreviewLayer
96
- labelGetter={(item: QueryBuilderVariableDragSource): string =>
97
- item.variable.name === '' ? '(unknown)' : item.variable.name
172
+ <ContextMenu
173
+ content={
174
+ <QueryBuilderVariableContextMenu
175
+ variable={variable}
176
+ variableInUse={isVariableUsed}
177
+ actions={actions}
178
+ extraContextMenuActions={extraContextMenuActions}
179
+ />
98
180
  }
99
- types={[QUERY_BUILDER_VARIABLE_DND_TYPE]}
100
- />
101
- <div
102
- onClick={editVariable}
103
- className="query-builder__variables__variable__content"
181
+ disabled={isReadOnly || !actions}
182
+ className={clsx('query-builder__variables__variable__context-menu', {
183
+ 'query-builder__variables__variable--selected-from-context-menu':
184
+ isSelectedFromContextMenu,
185
+ })}
186
+ menuProps={{ elevation: 7 }}
187
+ onOpen={onContextMenuOpen}
188
+ onClose={onContextMenuClose}
104
189
  >
105
- <div className="query-builder__variables__variable__icon">
106
- <div className="query-builder__variables__variable-icon">
107
- {constantValue ? (
108
- <div className="icon query-builder__variables__variable-icon">
109
- C
190
+ <DragPreviewLayer
191
+ labelGetter={(item: QueryBuilderVariableDragSource): string =>
192
+ item.variable.name === '' ? '(unknown)' : item.variable.name
193
+ }
194
+ types={[QUERY_BUILDER_VARIABLE_DND_TYPE]}
195
+ />
196
+ <div
197
+ onClick={editVariable}
198
+ className="query-builder__variables__variable__content"
199
+ >
200
+ <div className="query-builder__variables__variable__icon">
201
+ <div className="query-builder__variables__variable-icon">
202
+ {isConstant ? (
203
+ <div className="icon query-builder__variables__variable-icon">
204
+ C
205
+ </div>
206
+ ) : (
207
+ <DollarIcon />
208
+ )}
209
+ </div>
210
+ </div>
211
+ <div className="query-builder__variables__variable__label">
212
+ {name}
213
+ {isConstant ? (
214
+ <div
215
+ className={clsx('query-builder__constants__value', {
216
+ 'query-builder__constants__value--icon':
217
+ !constantValueString,
218
+ })}
219
+ >
220
+ {constantValueString}
221
+ {!constantValueString && (
222
+ <CalculatorIcon title="Calculated Constant" />
223
+ )}
110
224
  </div>
111
225
  ) : (
112
- <DollarIcon />
226
+ <div className="query-builder__variables__variable__type">
227
+ <div className="query-builder__variables__variable__type__label">
228
+ {variableTypeName ?? 'unknown'}
229
+ </div>
230
+ </div>
113
231
  )}
114
232
  </div>
115
233
  </div>
116
- <div className="query-builder__variables__variable__label">
117
- {name}
118
- {valueString ? (
119
- <div className="query-builder__constants__value">
120
- {valueString}
121
- </div>
122
- ) : (
123
- <div className="query-builder__variables__variable__type">
124
- <div className="query-builder__variables__variable__type__label">
125
- {typeName}
234
+ {actions && (
235
+ <div className="query-builder__variables__variable__actions">
236
+ <button
237
+ className="query-builder__variables__variable__action"
238
+ tabIndex={-1}
239
+ disabled={isReadOnly}
240
+ onClick={editVariable}
241
+ title="Edit"
242
+ >
243
+ <PencilIcon />
244
+ </button>
245
+ <button
246
+ className="query-builder__variables__variable__action"
247
+ tabIndex={-1}
248
+ onClick={deleteVariable}
249
+ disabled={deleteDisabled}
250
+ title={deleteTitle}
251
+ >
252
+ <TimesIcon />
253
+ </button>
254
+ <VariableInfoTooltip variable={variable}>
255
+ <div className="query-builder__variables__variable__action value-spec-editor__variable__info">
256
+ <InfoCircleIcon />
126
257
  </div>
127
- </div>
128
- )}
129
- </div>
130
- </div>
131
- {actions && (
132
- <div className="query-builder__variables__variable__actions">
133
- <button
134
- className="query-builder__variables__variable__action"
135
- tabIndex={-1}
136
- disabled={isReadOnly}
137
- onClick={editVariable}
138
- title="Edit"
139
- >
140
- <PencilIcon />
141
- </button>
142
- <button
143
- className="query-builder__variables__variable__action"
144
- tabIndex={-1}
145
- onClick={deleteVariable}
146
- disabled={deleteDisabled}
147
- title={deleteTitle}
148
- >
149
- <TimesIcon />
150
- </button>
151
- <VariableInfoTooltip variable={variable}>
152
- <div className="query-builder__variables__variable__action value-spec-editor__variable__info">
153
- <InfoCircleIcon />
154
- </div>
155
- </VariableInfoTooltip>
156
- </div>
157
- )}
258
+ </VariableInfoTooltip>
259
+ </div>
260
+ )}
261
+ </ContextMenu>
158
262
  </div>
159
263
  );
160
264
  },
@@ -166,7 +270,6 @@ export const VariableSelector = observer(
166
270
  filterBy?: (variableExpression: VariableExpression) => boolean;
167
271
  }) => {
168
272
  const { queryBuilderState, filterBy } = props;
169
- const isReadOnly = !queryBuilderState.isQuerySupported;
170
273
  const filteredParameterStates =
171
274
  queryBuilderState.parametersState.parameterStates.filter((p) =>
172
275
  filterBy ? filterBy(p.parameter) : true,
@@ -186,7 +289,7 @@ export const VariableSelector = observer(
186
289
  <VariableViewer
187
290
  key={pState.uuid}
188
291
  variable={pState.parameter}
189
- isReadOnly={isReadOnly}
292
+ isReadOnly={true}
190
293
  queryBuilderState={queryBuilderState}
191
294
  />
192
295
  ))}
@@ -197,9 +300,15 @@ export const VariableSelector = observer(
197
300
  <VariableViewer
198
301
  key={constantState.uuid}
199
302
  variable={constantState.variable}
200
- constantValue={constantState.value}
303
+ value={{
304
+ val:
305
+ constantState instanceof
306
+ QueryBuilderSimpleConstantExpressionState
307
+ ? constantState.value
308
+ : undefined,
309
+ }}
201
310
  queryBuilderState={queryBuilderState}
202
- isReadOnly={isReadOnly}
311
+ isReadOnly={true}
203
312
  />
204
313
  ))}
205
314
  </PanelFormListItems>
@@ -17,6 +17,7 @@
17
17
  export enum QUERY_BUILDER_SOURCE_ID_LABEL {
18
18
  QUERY_BUILDER = 'query-builder',
19
19
  PROJECTION = 'projection',
20
+ CONSTANT = 'constant',
20
21
  }
21
22
 
22
23
  export const DEFAULT_LAMBDA_VARIABLE_NAME = 'x';