@finos/legend-application-query 5.0.0 → 5.1.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.
- package/lib/components/QueryBuilderExplorerPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderExplorerPanel.js +3 -1
- package/lib/components/QueryBuilderExplorerPanel.js.map +1 -1
- package/lib/components/QueryBuilderFetchStructurePanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderFetchStructurePanel.js +39 -7
- package/lib/components/QueryBuilderFetchStructurePanel.js.map +1 -1
- package/lib/components/QueryBuilderFilterPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderFilterPanel.js +59 -15
- package/lib/components/QueryBuilderFilterPanel.js.map +1 -1
- package/lib/components/QueryBuilderFunctionsExplorerPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderFunctionsExplorerPanel.js.map +1 -1
- package/lib/components/QueryBuilderParameterPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderParameterPanel.js +3 -2
- package/lib/components/QueryBuilderParameterPanel.js.map +1 -1
- package/lib/components/QueryBuilderPostFilterPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderPostFilterPanel.js +29 -7
- package/lib/components/QueryBuilderPostFilterPanel.js.map +1 -1
- package/lib/components/QueryBuilderProjectionPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderProjectionPanel.js +6 -2
- package/lib/components/QueryBuilderProjectionPanel.js.map +1 -1
- package/lib/components/QueryBuilderPropertySearchPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderPropertySearchPanel.js +3 -2
- package/lib/components/QueryBuilderPropertySearchPanel.js.map +1 -1
- package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderResultPanel.js +13 -7
- package/lib/components/QueryBuilderResultPanel.js.map +1 -1
- package/lib/components/QueryBuilderSetupPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderSetupPanel.js +5 -3
- package/lib/components/QueryBuilderSetupPanel.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/package.json +2 -3
- package/lib/stores/QueryBuilderExplorerState.d.ts +1 -1
- package/lib/stores/QueryBuilderExplorerState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderExplorerState.js +13 -3
- package/lib/stores/QueryBuilderExplorerState.js.map +1 -1
- package/lib/stores/QueryBuilderFetchStructureState.d.ts +2 -1
- package/lib/stores/QueryBuilderFetchStructureState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderFetchStructureState.js +2 -2
- package/lib/stores/QueryBuilderFetchStructureState.js.map +1 -1
- package/lib/stores/QueryBuilderFilterState.d.ts +11 -1
- package/lib/stores/QueryBuilderFilterState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderFilterState.js +33 -2
- package/lib/stores/QueryBuilderFilterState.js.map +1 -1
- package/lib/stores/QueryBuilderOperatorLoader.d.ts +47 -0
- package/lib/stores/QueryBuilderOperatorLoader.d.ts.map +1 -0
- package/lib/stores/QueryBuilderOperatorLoader.js +94 -0
- package/lib/stores/QueryBuilderOperatorLoader.js.map +1 -0
- package/lib/stores/QueryBuilderOperatorsHelper.d.ts +1 -0
- package/lib/stores/QueryBuilderOperatorsHelper.d.ts.map +1 -1
- package/lib/stores/QueryBuilderOperatorsHelper.js +28 -1
- package/lib/stores/QueryBuilderOperatorsHelper.js.map +1 -1
- package/lib/stores/QueryBuilderPostFilterState.d.ts +5 -2
- package/lib/stores/QueryBuilderPostFilterState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderPostFilterState.js +25 -1
- package/lib/stores/QueryBuilderPostFilterState.js.map +1 -1
- package/lib/stores/QueryBuilderPreviewDataHelper.d.ts +4 -3
- package/lib/stores/QueryBuilderPreviewDataHelper.d.ts.map +1 -1
- package/lib/stores/QueryBuilderPreviewDataHelper.js +77 -97
- package/lib/stores/QueryBuilderPreviewDataHelper.js.map +1 -1
- package/lib/stores/QueryBuilderProjectionState.d.ts +4 -2
- package/lib/stores/QueryBuilderProjectionState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderProjectionState.js +24 -28
- package/lib/stores/QueryBuilderProjectionState.js.map +1 -1
- package/lib/stores/QueryBuilderPropertySearchPanelState.js +1 -1
- package/lib/stores/QueryBuilderPropertySearchPanelState.js.map +1 -1
- package/lib/stores/QueryBuilderResultState.d.ts +5 -2
- package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderResultState.js +19 -7
- package/lib/stores/QueryBuilderResultState.js.map +1 -1
- package/lib/stores/QueryBuilderState.d.ts +2 -0
- package/lib/stores/QueryBuilderState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderState.js +11 -58
- package/lib/stores/QueryBuilderState.js.map +1 -1
- package/lib/stores/QueryBuilderTestUtils.d.ts +24 -0
- package/lib/stores/QueryBuilderTestUtils.d.ts.map +1 -0
- package/lib/stores/QueryBuilderTestUtils.js +49 -0
- package/lib/stores/QueryBuilderTestUtils.js.map +1 -0
- package/lib/stores/QueryBuilderTypeaheadHelper.d.ts +24 -0
- package/lib/stores/QueryBuilderTypeaheadHelper.d.ts.map +1 -0
- package/lib/stores/QueryBuilderTypeaheadHelper.js +89 -0
- package/lib/stores/QueryBuilderTypeaheadHelper.js.map +1 -0
- package/lib/stores/QueryEditorStore.d.ts.map +1 -1
- package/lib/stores/QueryEditorStore.js +3 -7
- package/lib/stores/QueryEditorStore.js.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.d.ts.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.js +5 -31
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_Equal.js.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.d.ts.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.js +5 -31
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.js.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.js +5 -31
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.js.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.d.ts.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.js +5 -32
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThan.js.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.d.ts.map +1 -1
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.js +5 -31
- package/lib/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.js.map +1 -1
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.d.ts.map +1 -1
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.js +3 -29
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.js.map +1 -1
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.d.ts.map +1 -1
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.js +4 -30
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.js.map +1 -1
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.d.ts.map +1 -1
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.js +4 -30
- package/lib/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.js.map +1 -1
- package/package.json +9 -10
- package/src/components/QueryBuilderExplorerPanel.tsx +3 -1
- package/src/components/QueryBuilderFetchStructurePanel.tsx +47 -7
- package/src/components/QueryBuilderFilterPanel.tsx +101 -21
- package/src/components/QueryBuilderFunctionsExplorerPanel.tsx +1 -0
- package/src/components/QueryBuilderParameterPanel.tsx +3 -2
- package/src/components/QueryBuilderPostFilterPanel.tsx +53 -7
- package/src/components/QueryBuilderProjectionPanel.tsx +19 -2
- package/src/components/QueryBuilderPropertySearchPanel.tsx +2 -1
- package/src/components/QueryBuilderResultPanel.tsx +75 -46
- package/src/components/QueryBuilderSetupPanel.tsx +5 -3
- package/src/index.ts +2 -4
- package/src/stores/QueryBuilderExplorerState.ts +17 -3
- package/src/stores/QueryBuilderFetchStructureState.ts +9 -2
- package/src/stores/QueryBuilderFilterState.ts +50 -0
- package/src/stores/QueryBuilderOperatorLoader.ts +133 -0
- package/src/stores/QueryBuilderOperatorsHelper.ts +35 -0
- package/src/stores/QueryBuilderPostFilterState.ts +40 -1
- package/src/stores/QueryBuilderPreviewDataHelper.ts +122 -217
- package/src/stores/QueryBuilderProjectionState.ts +40 -42
- package/src/stores/QueryBuilderPropertySearchPanelState.ts +1 -1
- package/src/stores/QueryBuilderResultState.ts +27 -9
- package/src/stores/QueryBuilderState.ts +27 -94
- package/src/stores/QueryBuilderTestUtils.ts +93 -0
- package/src/stores/QueryBuilderTypeaheadHelper.ts +149 -0
- package/src/stores/QueryEditorStore.ts +11 -12
- package/src/stores/filterOperators/QueryBuilderFilterOperator_Equal.ts +6 -35
- package/src/stores/filterOperators/QueryBuilderFilterOperator_GreaterThan.ts +9 -35
- package/src/stores/filterOperators/QueryBuilderFilterOperator_GreaterThanEqual.ts +9 -35
- package/src/stores/filterOperators/QueryBuilderFilterOperator_LessThan.ts +9 -36
- package/src/stores/filterOperators/QueryBuilderFilterOperator_LessThanEqual.ts +9 -35
- package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_Equal.ts +6 -33
- package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_GreaterThan.ts +11 -36
- package/src/stores/postFilterOperators/QueryBuilderPostFilterOperator_LessThan.ts +11 -36
- package/tsconfig.json +3 -0
@@ -61,10 +61,18 @@ import {
|
|
61
61
|
assertErrorThrown,
|
62
62
|
guaranteeNonNullable,
|
63
63
|
returnUndefOnError,
|
64
|
+
debounce,
|
64
65
|
} from '@finos/legend-shared';
|
65
66
|
import { flowResult } from 'mobx';
|
66
67
|
import { observer } from 'mobx-react-lite';
|
67
|
-
import {
|
68
|
+
import {
|
69
|
+
forwardRef,
|
70
|
+
useCallback,
|
71
|
+
useEffect,
|
72
|
+
useMemo,
|
73
|
+
useRef,
|
74
|
+
useState,
|
75
|
+
} from 'react';
|
68
76
|
import {
|
69
77
|
type DropTargetMonitor,
|
70
78
|
useDragLayer,
|
@@ -74,7 +82,10 @@ import {
|
|
74
82
|
import { getEmptyImage } from 'react-dnd-html5-backend';
|
75
83
|
import { getColumnMultiplicity } from '../stores/postFilterOperators/QueryBuilderPostFilterOperatorHelper.js';
|
76
84
|
import { QueryBuilderAggregateColumnState } from '../stores/QueryBuilderAggregationState.js';
|
77
|
-
import {
|
85
|
+
import {
|
86
|
+
isTypeCompatibleWithConditionValueType,
|
87
|
+
QUERY_BUILDER_GROUP_OPERATION,
|
88
|
+
} from '../stores/QueryBuilderOperatorsHelper.js';
|
78
89
|
import type { QueryBuilderPostFilterOperator } from '../stores/QueryBuilderPostFilterOperator.js';
|
79
90
|
import {
|
80
91
|
type QueryBuilderPostFilterTreeNodeData,
|
@@ -405,6 +416,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
405
416
|
const { node, isPropertyDragOver } = props;
|
406
417
|
const graph =
|
407
418
|
node.condition.postFilterState.queryBuilderState.graphManagerState.graph;
|
419
|
+
const applicationStore = useApplicationStore();
|
408
420
|
const changeOperator = (val: QueryBuilderPostFilterOperator) => (): void =>
|
409
421
|
node.condition.changeOperator(val);
|
410
422
|
const changeColumn = async (
|
@@ -421,9 +433,24 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
421
433
|
// Drag and Drop on filter condition value
|
422
434
|
const handleDrop = useCallback(
|
423
435
|
(item: QueryBuilderParameterDragSource): void => {
|
424
|
-
|
436
|
+
const parameterType =
|
437
|
+
item.variable.parameter.genericType?.value.rawType;
|
438
|
+
const conditionValueType = node.condition.columnState.getReturnType();
|
439
|
+
if (
|
440
|
+
conditionValueType &&
|
441
|
+
isTypeCompatibleWithConditionValueType(
|
442
|
+
parameterType,
|
443
|
+
conditionValueType,
|
444
|
+
)
|
445
|
+
) {
|
446
|
+
node.condition.setValue(item.variable.parameter);
|
447
|
+
} else {
|
448
|
+
applicationStore.notifyWarning(
|
449
|
+
`Incompatible parameter type ${parameterType?.name}. ${parameterType?.name} is not compatible with type ${conditionValueType?.name}.`,
|
450
|
+
);
|
451
|
+
}
|
425
452
|
},
|
426
|
-
[node],
|
453
|
+
[applicationStore, node.condition],
|
427
454
|
);
|
428
455
|
const [{ isFilterValueDragOver }, dropConnector] = useDrop(
|
429
456
|
() => ({
|
@@ -447,6 +474,26 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
447
474
|
node.condition.operator.getDefaultFilterConditionValue(node.condition),
|
448
475
|
);
|
449
476
|
};
|
477
|
+
const debouncedTypeaheadSearch = useMemo(
|
478
|
+
() =>
|
479
|
+
debounce(
|
480
|
+
(inputVal: string) => node.condition.handleTypeaheadSearch(),
|
481
|
+
1000,
|
482
|
+
),
|
483
|
+
[node],
|
484
|
+
);
|
485
|
+
const cleanUpReloadValues = (): void => {
|
486
|
+
node.condition.typeaheadSearchState.complete();
|
487
|
+
};
|
488
|
+
const changeValueSpecification = (val: ValueSpecification): void => {
|
489
|
+
node.condition.setValue(val);
|
490
|
+
};
|
491
|
+
const selectorConfig = {
|
492
|
+
values: node.condition.typeaheadSearchResults,
|
493
|
+
isLoading: node.condition.typeaheadSearchState.isInProgress,
|
494
|
+
reloadValues: debouncedTypeaheadSearch,
|
495
|
+
cleanUpReloadValues,
|
496
|
+
};
|
450
497
|
|
451
498
|
return (
|
452
499
|
<div className="query-builder-post-filter-tree__node__label__content dnd__overlay__container">
|
@@ -506,9 +553,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
506
553
|
)}
|
507
554
|
<BasicValueSpecificationEditor
|
508
555
|
valueSpecification={node.condition.value}
|
509
|
-
setValueSpecification={
|
510
|
-
node.condition.setValue(val)
|
511
|
-
}
|
556
|
+
setValueSpecification={changeValueSpecification}
|
512
557
|
graph={graph}
|
513
558
|
typeCheckOption={{
|
514
559
|
expectedType: guaranteeNonNullable(
|
@@ -516,6 +561,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
516
561
|
),
|
517
562
|
}}
|
518
563
|
resetValue={resetNode}
|
564
|
+
selectorConfig={selectorConfig}
|
519
565
|
/>
|
520
566
|
</div>
|
521
567
|
)}
|
@@ -28,6 +28,7 @@ import {
|
|
28
28
|
ContextMenu,
|
29
29
|
InputWithInlineValidation,
|
30
30
|
SigmaIcon,
|
31
|
+
TimesCircleIcon,
|
31
32
|
} from '@finos/legend-art';
|
32
33
|
import {
|
33
34
|
type QueryBuilderExplorerTreeDragSource,
|
@@ -588,6 +589,8 @@ export const QueryBuilderProjectionPanel = observer(
|
|
588
589
|
},
|
589
590
|
[queryBuilderState, projectionState],
|
590
591
|
);
|
592
|
+
|
593
|
+
const isInvalidProjection = !projectionState.isValidProjectionState();
|
591
594
|
const [{ isPropertyDragOver }, dropConnector] = useDrop(
|
592
595
|
() => ({
|
593
596
|
accept: [
|
@@ -620,10 +623,21 @@ export const QueryBuilderProjectionPanel = observer(
|
|
620
623
|
|
621
624
|
return (
|
622
625
|
<div
|
623
|
-
className="panel__content dnd__overlay__container"
|
624
626
|
ref={dropConnector}
|
627
|
+
className={`panel__content dnd__overlay__container`}
|
625
628
|
>
|
629
|
+
{isInvalidProjection && (
|
630
|
+
<div className="query-builder__projection__container__error">
|
631
|
+
<div className="query-builder__projection__error__label">
|
632
|
+
<TimesCircleIcon className="query-builder__projection__error__icon" />
|
633
|
+
{projectionState.getValidationErrorMessage() ??
|
634
|
+
'There is an error with the projection'}
|
635
|
+
</div>
|
636
|
+
</div>
|
637
|
+
)}
|
638
|
+
|
626
639
|
<div className={clsx({ dnd__overlay: isPropertyDragOver })} />
|
640
|
+
|
627
641
|
{!projectionColumns.length && (
|
628
642
|
<BlankPanelPlaceholder
|
629
643
|
placeholderText="Add a projection column"
|
@@ -633,7 +647,10 @@ export const QueryBuilderProjectionPanel = observer(
|
|
633
647
|
{Boolean(projectionColumns.length) && (
|
634
648
|
<div
|
635
649
|
data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_PROJECTION}
|
636
|
-
className=
|
650
|
+
className={`query-builder__projection__columns ${clsx({
|
651
|
+
['query-builder__projection__columns--with-error']:
|
652
|
+
isInvalidProjection,
|
653
|
+
})} `}
|
637
654
|
>
|
638
655
|
<ProjectionColumnDragLayer />
|
639
656
|
{projectionColumns.map((projectionColumnState) => (
|
@@ -169,6 +169,7 @@ const QueryBuilderTreeNodeViewer = observer(
|
|
169
169
|
),
|
170
170
|
);
|
171
171
|
if (
|
172
|
+
propertyTreeNodeData &&
|
172
173
|
!(propertyTreeNodeData.type instanceof Class) &&
|
173
174
|
propertyTreeNodeData.mappingData.mapped
|
174
175
|
) {
|
@@ -192,7 +193,7 @@ const QueryBuilderTreeNodeViewer = observer(
|
|
192
193
|
return (
|
193
194
|
<div>
|
194
195
|
<div
|
195
|
-
className="tree-view__node__container"
|
196
|
+
className="tree-view__node__container query-builder-property-search-panel__node__container"
|
196
197
|
ref={dragConnector}
|
197
198
|
style={{
|
198
199
|
paddingLeft: `${(level - 1) * stepPaddingInRem + 0.5}rem`,
|
@@ -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';
|
@@ -413,27 +414,32 @@ export const QueryBuilderResultPanel = observer(
|
|
413
414
|
],
|
414
415
|
});
|
415
416
|
};
|
416
|
-
const
|
417
|
+
const runQuery = (): void => {
|
417
418
|
if (queryParametersState.parameterStates.length) {
|
418
419
|
queryParametersState.parameterValuesEditorState.open(
|
419
420
|
(): Promise<void> =>
|
420
|
-
flowResult(resultState.
|
421
|
+
flowResult(resultState.runQuery()).catch(
|
421
422
|
applicationStore.alertUnhandledError,
|
422
423
|
),
|
423
424
|
PARAMETER_SUBMIT_ACTION.EXECUTE,
|
424
425
|
);
|
425
426
|
} else {
|
426
|
-
flowResult(resultState.
|
427
|
+
flowResult(resultState.runQuery()).catch(
|
427
428
|
applicationStore.alertUnhandledError,
|
428
429
|
);
|
429
430
|
}
|
430
431
|
};
|
432
|
+
const cancelQuery = (): void => {
|
433
|
+
resultState.setIsRunningQuery(false);
|
434
|
+
queryBuilderState.resultState.setQueryRunPromise(undefined);
|
435
|
+
};
|
431
436
|
const generatePlan = applicationStore.guardUnhandledError(() =>
|
432
437
|
flowResult(resultState.generatePlan(false)),
|
433
438
|
);
|
434
439
|
const debugPlanGeneration = applicationStore.guardUnhandledError(() =>
|
435
440
|
flowResult(resultState.generatePlan(true)),
|
436
441
|
);
|
442
|
+
|
437
443
|
const changeLimit: React.ChangeEventHandler<HTMLInputElement> = (event) => {
|
438
444
|
const val = event.target.value;
|
439
445
|
queryBuilderState.resultState.setPreviewLimit(
|
@@ -469,52 +475,70 @@ export const QueryBuilderResultPanel = observer(
|
|
469
475
|
type="number"
|
470
476
|
value={resultState.previewLimit}
|
471
477
|
onChange={changeLimit}
|
478
|
+
disabled={!queryBuilderState.isValidQueryBuilderState()}
|
472
479
|
/>
|
473
480
|
</div>
|
474
481
|
)}
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
482
|
+
{resultState.isRunningQuery ? (
|
483
|
+
<button
|
484
|
+
className="query-builder__result__stop-btn"
|
485
|
+
onClick={cancelQuery}
|
486
|
+
tabIndex={-1}
|
487
|
+
disabled={!queryBuilderState.isValidQueryBuilderState()}
|
488
|
+
>
|
489
|
+
<div className="btn--dark btn--caution query-builder__result__stop-btn__label">
|
490
|
+
<PauseCircleIcon className="query-builder__result__stop-btn__label__icon" />
|
491
|
+
<div className="query-builder__result__stop-btn__label__title">
|
492
|
+
Stop
|
493
|
+
</div>
|
487
494
|
</div>
|
488
|
-
</
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
}
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
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>
|
495
|
+
</button>
|
496
|
+
) : (
|
497
|
+
<button
|
498
|
+
className="query-builder__result__execute-btn"
|
499
|
+
onClick={runQuery}
|
500
|
+
tabIndex={-1}
|
501
|
+
title={
|
502
|
+
!queryBuilderState.isValidQueryBuilderState()
|
503
|
+
? 'Query is not valid'
|
504
|
+
: undefined
|
509
505
|
}
|
510
|
-
|
511
|
-
anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
|
512
|
-
transformOrigin: { vertical: 'top', horizontal: 'right' },
|
513
|
-
}}
|
506
|
+
disabled={!queryBuilderState.isValidQueryBuilderState()}
|
514
507
|
>
|
515
|
-
<
|
516
|
-
|
517
|
-
|
508
|
+
<div className="query-builder__result__execute-btn__label">
|
509
|
+
<PlayIcon className="query-builder__result__execute-btn__label__icon" />
|
510
|
+
<div className="query-builder__result__execute-btn__label__title">
|
511
|
+
Run Query
|
512
|
+
</div>
|
513
|
+
</div>
|
514
|
+
<DropdownMenu
|
515
|
+
className="query-builder__result__execute-btn__dropdown-btn"
|
516
|
+
disabled={resultState.isGeneratingPlan}
|
517
|
+
content={
|
518
|
+
<MenuContent>
|
519
|
+
<MenuContentItem
|
520
|
+
className="query-builder__result__execute-btn__option"
|
521
|
+
onClick={generatePlan}
|
522
|
+
>
|
523
|
+
Generate Plan
|
524
|
+
</MenuContentItem>
|
525
|
+
<MenuContentItem
|
526
|
+
className="query-builder__result__execute-btn__option"
|
527
|
+
onClick={debugPlanGeneration}
|
528
|
+
>
|
529
|
+
Debug
|
530
|
+
</MenuContentItem>
|
531
|
+
</MenuContent>
|
532
|
+
}
|
533
|
+
menuProps={{
|
534
|
+
anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
|
535
|
+
transformOrigin: { vertical: 'top', horizontal: 'right' },
|
536
|
+
}}
|
537
|
+
>
|
538
|
+
<CaretDownIcon />
|
539
|
+
</DropdownMenu>
|
540
|
+
</button>
|
541
|
+
)}
|
518
542
|
<DropdownMenu
|
519
543
|
className="query-builder__result__export__dropdown"
|
520
544
|
content={
|
@@ -542,19 +566,24 @@ export const QueryBuilderResultPanel = observer(
|
|
542
566
|
className="query-builder__result__export__dropdown__label"
|
543
567
|
tabIndex={-1}
|
544
568
|
title="Export"
|
569
|
+
disabled={!queryBuilderState.isValidQueryBuilderState()}
|
545
570
|
>
|
546
571
|
Export
|
547
572
|
</button>
|
548
|
-
<
|
573
|
+
<button
|
574
|
+
className="query-builder__result__export__dropdown__trigger"
|
575
|
+
tabIndex={-1}
|
576
|
+
disabled={!queryBuilderState.isValidQueryBuilderState()}
|
577
|
+
>
|
549
578
|
<CaretDownIcon />
|
550
|
-
</
|
579
|
+
</button>
|
551
580
|
</DropdownMenu>
|
552
581
|
</div>
|
553
582
|
</div>
|
554
583
|
<div className="panel__content">
|
555
584
|
<PanelLoadingIndicator
|
556
585
|
isLoading={
|
557
|
-
resultState.
|
586
|
+
resultState.isRunningQuery ||
|
558
587
|
resultState.isGeneratingPlan ||
|
559
588
|
resultState.exportDataState.isInProgress
|
560
589
|
}
|
@@ -46,7 +46,7 @@ import {
|
|
46
46
|
} from '@finos/legend-graph';
|
47
47
|
import {
|
48
48
|
type PackageableElementOption,
|
49
|
-
|
49
|
+
getPackageableElementOptionFormatter,
|
50
50
|
buildElementOption,
|
51
51
|
} from '@finos/legend-application';
|
52
52
|
import { MilestoningParametersEditor } from './QueryBuilderMilestoneEditor.js';
|
@@ -269,8 +269,9 @@ export const QueryBuilderSetupPanel = observer(
|
|
269
269
|
darkMode={true}
|
270
270
|
disabled={!isQuerySupported || querySetupState.classIsReadOnly}
|
271
271
|
filterOption={elementFilterOption}
|
272
|
-
formatOptionLabel={
|
272
|
+
formatOptionLabel={getPackageableElementOptionFormatter({
|
273
273
|
darkMode: true,
|
274
|
+
graphManagerState: queryBuilderState.graphManagerState,
|
274
275
|
})}
|
275
276
|
/>
|
276
277
|
<button
|
@@ -304,8 +305,9 @@ export const QueryBuilderSetupPanel = observer(
|
|
304
305
|
value={selectedMappingOption}
|
305
306
|
darkMode={true}
|
306
307
|
filterOption={elementFilterOption}
|
307
|
-
formatOptionLabel={
|
308
|
+
formatOptionLabel={getPackageableElementOptionFormatter({
|
308
309
|
darkMode: true,
|
310
|
+
graphManagerState: queryBuilderState.graphManagerState,
|
309
311
|
})}
|
310
312
|
/>
|
311
313
|
</div>
|
package/src/index.ts
CHANGED
@@ -15,6 +15,8 @@
|
|
15
15
|
*/
|
16
16
|
|
17
17
|
export * from './application/LegendQuery.js';
|
18
|
+
export * from './components/LegendQueryBaseStoreProvider.js';
|
19
|
+
export * from './stores/LegendQueryBaseStore.js';
|
18
20
|
|
19
21
|
export { QUERY_BUILDER_TEST_ID } from './components/QueryBuilder_TestID.js';
|
20
22
|
|
@@ -26,10 +28,6 @@ export {
|
|
26
28
|
useQueryEditorStore,
|
27
29
|
} from './components/QueryEditorStoreProvider.js';
|
28
30
|
export { useQuerySetupStore } from './components/QuerySetupStoreProvider.js';
|
29
|
-
export {
|
30
|
-
useLegendQueryBaseStore,
|
31
|
-
useLegendQueryApplicationStore,
|
32
|
-
} from './components/LegendQueryBaseStoreProvider.js';
|
33
31
|
export { QueryEditor } from './components/QueryEditor.js';
|
34
32
|
|
35
33
|
export { LegendQueryPluginManager } from './application/LegendQueryPluginManager.js';
|
@@ -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,16 @@ export const getQueryBuilderPropertyNodeData = (
|
|
353
355
|
parentNode.isPartOfDerivedPropertyBranch ||
|
354
356
|
(parentNode instanceof QueryBuilderExplorerTreePropertyNodeData &&
|
355
357
|
parentNode.property instanceof DerivedProperty);
|
358
|
+
if (
|
359
|
+
property instanceof Property &&
|
360
|
+
parentNode instanceof QueryBuilderExplorerTreePropertyNodeData &&
|
361
|
+
parentNode.property instanceof Property &&
|
362
|
+
property._OWNER instanceof Association &&
|
363
|
+
parentNode.property._OWNER instanceof Association &&
|
364
|
+
parentNode.property._OWNER === property._OWNER
|
365
|
+
) {
|
366
|
+
return undefined;
|
367
|
+
}
|
356
368
|
const propertyNode = new QueryBuilderExplorerTreePropertyNodeData(
|
357
369
|
`${
|
358
370
|
parentNode instanceof QueryBuilderExplorerTreeRootNodeData
|
@@ -455,8 +467,10 @@ const getQueryBuilderTreeData = (
|
|
455
467
|
treeRootNode,
|
456
468
|
modelCoverageAnalysisResult,
|
457
469
|
);
|
458
|
-
|
459
|
-
|
470
|
+
if (propertyTreeNodeData) {
|
471
|
+
addUniqueEntry(treeRootNode.childrenIds, propertyTreeNodeData.id);
|
472
|
+
nodes.set(propertyTreeNodeData.id, propertyTreeNodeData);
|
473
|
+
}
|
460
474
|
});
|
461
475
|
rootClass._subclasses.forEach((subclass) => {
|
462
476
|
const subTypeTreeNodeData = getQueryBuilderSubTypeNodeData(
|
@@ -18,6 +18,7 @@ import { action, makeAutoObservable } from 'mobx';
|
|
18
18
|
import type { QueryBuilderState } from './QueryBuilderState.js';
|
19
19
|
import { QueryBuilderGraphFetchTreeState } from './QueryBuilderGraphFetchTreeState.js';
|
20
20
|
import { QueryBuilderProjectionState } from './QueryBuilderProjectionState.js';
|
21
|
+
import type { QueryBuilderAggregateOperator } from './QueryBuilderAggregationState.js';
|
21
22
|
|
22
23
|
export enum FETCH_STRUCTURE_MODE {
|
23
24
|
PROJECTION = 'PROJECTION',
|
@@ -30,7 +31,10 @@ export class QueryBuilderFetchStructureState {
|
|
30
31
|
projectionState: QueryBuilderProjectionState;
|
31
32
|
graphFetchTreeState: QueryBuilderGraphFetchTreeState;
|
32
33
|
|
33
|
-
constructor(
|
34
|
+
constructor(
|
35
|
+
queryBuilderState: QueryBuilderState,
|
36
|
+
operators: QueryBuilderAggregateOperator[],
|
37
|
+
) {
|
34
38
|
makeAutoObservable(this, {
|
35
39
|
queryBuilderState: false,
|
36
40
|
setFetchStructureMode: action,
|
@@ -39,7 +43,10 @@ export class QueryBuilderFetchStructureState {
|
|
39
43
|
this.queryBuilderState = queryBuilderState;
|
40
44
|
// TODO: we probably should modularize this a bit better
|
41
45
|
// See https://github.com/finos/legend-studio/issues/731
|
42
|
-
this.projectionState = new QueryBuilderProjectionState(
|
46
|
+
this.projectionState = new QueryBuilderProjectionState(
|
47
|
+
queryBuilderState,
|
48
|
+
operators,
|
49
|
+
);
|
43
50
|
this.graphFetchTreeState = new QueryBuilderGraphFetchTreeState(
|
44
51
|
queryBuilderState,
|
45
52
|
);
|
@@ -20,9 +20,11 @@ import {
|
|
20
20
|
makeAutoObservable,
|
21
21
|
makeObservable,
|
22
22
|
observable,
|
23
|
+
flow,
|
23
24
|
} from 'mobx';
|
24
25
|
import type { TreeNodeData, TreeData } from '@finos/legend-art';
|
25
26
|
import {
|
27
|
+
type GeneratorFn,
|
26
28
|
assertTrue,
|
27
29
|
getNullableFirstElement,
|
28
30
|
guaranteeNonNullable,
|
@@ -34,11 +36,13 @@ import {
|
|
34
36
|
deleteEntry,
|
35
37
|
assertErrorThrown,
|
36
38
|
filterByType,
|
39
|
+
ActionState,
|
37
40
|
} from '@finos/legend-shared';
|
38
41
|
import type { QueryBuilderExplorerTreeDragSource } from './QueryBuilderExplorerState.js';
|
39
42
|
import { QueryBuilderPropertyExpressionState } from './QueryBuilderPropertyEditorState.js';
|
40
43
|
import type { QueryBuilderState } from './QueryBuilderState.js';
|
41
44
|
import {
|
45
|
+
type ExecutionResult,
|
42
46
|
type AbstractPropertyExpression,
|
43
47
|
type ValueSpecification,
|
44
48
|
extractElementNameFromPath,
|
@@ -55,6 +59,12 @@ import {
|
|
55
59
|
fromGroupOperation,
|
56
60
|
QUERY_BUILDER_GROUP_OPERATION,
|
57
61
|
} from './QueryBuilderOperatorsHelper.js';
|
62
|
+
import type { QueryBuilderProjectionColumnDragSource } from './QueryBuilderProjectionState.js';
|
63
|
+
import {
|
64
|
+
buildPropertyTypeAheadQuery,
|
65
|
+
buildTypeAheadOptions,
|
66
|
+
performTypeAhead,
|
67
|
+
} from './QueryBuilderTypeaheadHelper.js';
|
58
68
|
|
59
69
|
export abstract class QueryBuilderFilterOperator {
|
60
70
|
readonly uuid = uuid();
|
@@ -95,6 +105,7 @@ export interface QueryBuilderFilterConditionDragSource {
|
|
95
105
|
|
96
106
|
export type QueryBuilderFilterDropTarget =
|
97
107
|
| QueryBuilderExplorerTreeDragSource
|
108
|
+
| QueryBuilderProjectionColumnDragSource
|
98
109
|
| QueryBuilderFilterConditionDragSource;
|
99
110
|
export type QueryBuilderFilterConditionRearrangeDropTarget =
|
100
111
|
QueryBuilderFilterConditionDragSource;
|
@@ -105,6 +116,8 @@ export class FilterConditionState {
|
|
105
116
|
operator!: QueryBuilderFilterOperator;
|
106
117
|
value?: ValueSpecification | undefined;
|
107
118
|
existsLambdaParamNames: string[] = [];
|
119
|
+
typeaheadSearchResults: string[] | undefined;
|
120
|
+
typeaheadSearchState = ActionState.create();
|
108
121
|
|
109
122
|
constructor(
|
110
123
|
filterState: QueryBuilderFilterState,
|
@@ -117,7 +130,10 @@ export class FilterConditionState {
|
|
117
130
|
changeOperator: action,
|
118
131
|
setOperator: action,
|
119
132
|
setValue: action,
|
133
|
+
typeaheadSearchResults: observable,
|
134
|
+
typeaheadSearchState: observable,
|
120
135
|
addExistsLambdaParamNames: action,
|
136
|
+
handleTypeaheadSearch: flow,
|
121
137
|
});
|
122
138
|
|
123
139
|
this.filterState = filterState;
|
@@ -141,6 +157,35 @@ export class FilterConditionState {
|
|
141
157
|
);
|
142
158
|
}
|
143
159
|
|
160
|
+
*handleTypeaheadSearch(): GeneratorFn<void> {
|
161
|
+
try {
|
162
|
+
this.typeaheadSearchState.inProgress();
|
163
|
+
this.typeaheadSearchResults = undefined;
|
164
|
+
if (performTypeAhead(this.value)) {
|
165
|
+
const builderState = buildPropertyTypeAheadQuery(
|
166
|
+
this.filterState.queryBuilderState,
|
167
|
+
this.propertyExpressionState.propertyExpression,
|
168
|
+
this.value,
|
169
|
+
);
|
170
|
+
const result =
|
171
|
+
(yield builderState.graphManagerState.graphManager.executeMapping(
|
172
|
+
builderState.resultState.buildExecutionRawLambda(),
|
173
|
+
guaranteeNonNullable(builderState.querySetupState.mapping),
|
174
|
+
guaranteeNonNullable(builderState.querySetupState.runtimeValue),
|
175
|
+
builderState.graphManagerState.graph,
|
176
|
+
)) as ExecutionResult;
|
177
|
+
this.typeaheadSearchResults = buildTypeAheadOptions(result);
|
178
|
+
}
|
179
|
+
this.typeaheadSearchState.pass();
|
180
|
+
} catch (error) {
|
181
|
+
assertErrorThrown(error);
|
182
|
+
this.typeaheadSearchResults = [];
|
183
|
+
this.typeaheadSearchState.fail();
|
184
|
+
} finally {
|
185
|
+
this.typeaheadSearchState.complete();
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
144
189
|
changeProperty(propertyExpression: AbstractPropertyExpression): void {
|
145
190
|
try {
|
146
191
|
// first, check if the new property is supported
|
@@ -407,6 +452,11 @@ export class QueryBuilderFilterState
|
|
407
452
|
isRearrangingConditions = false;
|
408
453
|
operators: QueryBuilderFilterOperator[] = [];
|
409
454
|
private _suppressClickawayEventListener = false;
|
455
|
+
/**
|
456
|
+
* This flag is for turning on/off dnd from projection panel to filter panel,
|
457
|
+
* and will be leveraged when the concepts of workflows are introduced into query builder.
|
458
|
+
*/
|
459
|
+
allowDnDProjectionToFilter = true;
|
410
460
|
|
411
461
|
constructor(
|
412
462
|
queryBuilderState: QueryBuilderState,
|