@finos/legend-query-builder 2.1.6 → 2.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (21) hide show
  1. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  2. package/lib/components/QueryBuilderResultPanel.js +12 -12
  3. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  4. package/lib/components/fetch-structure/QueryBuilderGraphFetchTreePanel.d.ts +12 -2
  5. package/lib/components/fetch-structure/QueryBuilderGraphFetchTreePanel.d.ts.map +1 -1
  6. package/lib/components/fetch-structure/QueryBuilderGraphFetchTreePanel.js +145 -20
  7. package/lib/components/fetch-structure/QueryBuilderGraphFetchTreePanel.js.map +1 -1
  8. package/lib/index.css +1 -17
  9. package/lib/index.css.map +1 -1
  10. package/lib/package.json +1 -1
  11. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.d.ts +3 -0
  12. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.d.ts.map +1 -1
  13. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js +19 -1
  14. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js.map +1 -1
  15. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeValueSpecificationBuilder.js +11 -11
  16. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeValueSpecificationBuilder.js.map +1 -1
  17. package/package.json +4 -4
  18. package/src/components/QueryBuilderResultPanel.tsx +17 -14
  19. package/src/components/fetch-structure/QueryBuilderGraphFetchTreePanel.tsx +384 -63
  20. package/src/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.ts +34 -0
  21. package/src/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeValueSpecificationBuilder.ts +11 -11
@@ -41,9 +41,21 @@ import {
41
41
  ModalFooterButton,
42
42
  ModalFooter,
43
43
  SerializeIcon,
44
+ ResizablePanel,
45
+ ResizablePanelSplitter,
46
+ ResizablePanelGroup,
47
+ BufferIcon,
48
+ CustomSelectorInput,
49
+ FolderIcon,
44
50
  } from '@finos/legend-art';
45
51
  import { QUERY_BUILDER_TEST_ID } from '../../application/QueryBuilderTesting.js';
46
- import { isNonNullable } from '@finos/legend-shared';
52
+ import {
53
+ deepClone,
54
+ filterByType,
55
+ guaranteeNonNullable,
56
+ isNonNullable,
57
+ prettyCONSTName,
58
+ } from '@finos/legend-shared';
47
59
  import {
48
60
  type QueryBuilderGraphFetchTreeData,
49
61
  type QueryBuilderGraphFetchTreeNodeData,
@@ -55,12 +67,51 @@ import {
55
67
  QUERY_BUILDER_EXPLORER_TREE_DND_TYPE,
56
68
  } from '../../stores/explorer/QueryBuilderExplorerState.js';
57
69
  import {
70
+ type GraphFetchSerializationState,
71
+ GraphFetchExternalFormatSerializationState,
58
72
  GraphFetchPureSerializationState,
59
73
  PureSerializationConfig,
74
+ SERIALIZATION_TYPE,
60
75
  type QueryBuilderGraphFetchTreeState,
61
76
  } from '../../stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js';
62
77
  import { getClassPropertyIcon } from '../shared/ElementIconUtils.js';
63
78
  import { QueryBuilderTextEditorMode } from '../../stores/QueryBuilderTextEditorState.js';
79
+ import {
80
+ type PackageableElement,
81
+ Binding,
82
+ Package,
83
+ getDescendantsOfPackage,
84
+ } from '@finos/legend-graph';
85
+ import {
86
+ ActionAlertActionType,
87
+ ActionAlertType,
88
+ buildElementOption,
89
+ type PackageableElementOption,
90
+ } from '@finos/legend-application';
91
+
92
+ const getBindingFormatter = (props: {
93
+ darkMode?: boolean;
94
+ }): ((
95
+ option: PackageableElementOption<PackageableElement>,
96
+ ) => React.ReactNode) =>
97
+ function BindingLabel(
98
+ option: PackageableElementOption<PackageableElement>,
99
+ ): React.ReactNode {
100
+ const className = props.darkMode
101
+ ? 'packageable-element-option-label--dark'
102
+ : 'packageable-element-option-label';
103
+ return (
104
+ <div className={className}>
105
+ <div className={`${className}__name`}>{option.label}</div>
106
+ {option.value.package && (
107
+ <div className={`${className}__tag`}>{option.value.path}</div>
108
+ )}
109
+ <div className={`${className}__tag`}>
110
+ {(option.value as Binding).contentType}
111
+ </div>
112
+ </div>
113
+ );
114
+ };
64
115
 
65
116
  const QueryBuilderGraphFetchTreeNodeContainer: React.FC<
66
117
  TreeNodeContainerProps<
@@ -287,22 +338,131 @@ const PureSerializationConfigModal = observer(
287
338
  },
288
339
  );
289
340
 
341
+ export const QueryBuilderGraphFetchExternalConfig = observer(
342
+ (props: {
343
+ graphFetchState: QueryBuilderGraphFetchTreeState;
344
+ serializationState: GraphFetchExternalFormatSerializationState;
345
+ serializationTreeData: QueryBuilderGraphFetchTreeData;
346
+ bindings: Binding[];
347
+ isReadOnly: boolean;
348
+ }) => {
349
+ const {
350
+ graphFetchState,
351
+ serializationState,
352
+ serializationTreeData,
353
+ bindings,
354
+ isReadOnly,
355
+ } = props;
356
+ const bindingOptions = bindings.map((result) => buildElementOption(result));
357
+ const selectedBinding = {
358
+ value: serializationState.targetBinding,
359
+ label: serializationState.targetBinding.name,
360
+ };
361
+ const onBindingChange = (
362
+ val: PackageableElementOption<Binding> | null,
363
+ ): void => {
364
+ if (val !== null) {
365
+ serializationState.setBinding(val.value);
366
+ serializationState.setGraphFetchTree(serializationTreeData);
367
+ }
368
+ };
369
+ const onNodeSelect = (node: QueryBuilderGraphFetchTreeNodeData): void => {
370
+ if (node.childrenIds.length) {
371
+ node.isOpen = !node.isOpen;
372
+ }
373
+ };
374
+ const getChildNodes = (
375
+ node: QueryBuilderGraphFetchTreeNodeData,
376
+ ): QueryBuilderGraphFetchTreeNodeData[] =>
377
+ node.childrenIds
378
+ .map((id) => serializationTreeData.nodes.get(id))
379
+ .filter(isNonNullable);
380
+ const removeNode = (node: QueryBuilderGraphFetchTreeNodeData): void => {
381
+ if (serializationTreeData.nodes.size === 1) {
382
+ graphFetchState.queryBuilderState.applicationStore.notificationService.notifyWarning(
383
+ 'externalize serialization tree can not be empty',
384
+ );
385
+ } else {
386
+ removeNodeRecursively(serializationTreeData, node);
387
+ serializationState.setGraphFetchTree({ ...serializationTreeData });
388
+ }
389
+ };
390
+
391
+ return (
392
+ <div className="query-builder-graph-fetch-external-format">
393
+ <div className="service-execution-editor__configuration__items">
394
+ <div className="service-execution-editor__configuration__item">
395
+ <div className="btn--sm service-execution-editor__configuration__item__label">
396
+ <BufferIcon />
397
+ </div>
398
+ <CustomSelectorInput
399
+ className="panel__content__form__section__dropdown service-execution-editor__configuration__item__dropdown"
400
+ disabled={isReadOnly}
401
+ options={bindingOptions}
402
+ onChange={onBindingChange}
403
+ value={selectedBinding}
404
+ formatOptionLabel={getBindingFormatter({
405
+ darkMode: true,
406
+ })}
407
+ darkMode={true}
408
+ />
409
+ </div>
410
+ <div className="service-execution-editor__configuration__item">
411
+ <div className="btn--sm service-execution-editor__configuration__item__label">
412
+ <FolderIcon />
413
+ </div>
414
+ <TreeView
415
+ components={{
416
+ TreeNodeContainer: QueryBuilderGraphFetchTreeNodeContainer,
417
+ }}
418
+ className="query-builder-graph-fetch-tree__container__tree"
419
+ treeData={serializationTreeData}
420
+ onNodeSelect={onNodeSelect}
421
+ getChildNodes={getChildNodes}
422
+ innerProps={{
423
+ isReadOnly,
424
+ removeNode,
425
+ }}
426
+ />
427
+ </div>
428
+ </div>
429
+ </div>
430
+ );
431
+ },
432
+ );
433
+
290
434
  export const QueryBuilderGraphFetchTreeExplorer = observer(
291
435
  (props: {
292
436
  graphFetchState: QueryBuilderGraphFetchTreeState;
293
- pureSerializationState: GraphFetchPureSerializationState;
437
+ serializationState: GraphFetchSerializationState;
294
438
  treeData: QueryBuilderGraphFetchTreeData;
295
439
  updateTreeData: (data: QueryBuilderGraphFetchTreeData) => void;
296
440
  isReadOnly: boolean;
297
441
  }) => {
298
442
  const {
299
443
  graphFetchState,
300
- pureSerializationState,
444
+ serializationState,
301
445
  treeData,
302
446
  updateTreeData,
303
447
  isReadOnly,
304
448
  } = props;
305
449
 
450
+ // Retrieve all bindings whose packageableElementIncludes contain the root class of main graph fetch tree
451
+ const compatibleBindings =
452
+ graphFetchState.queryBuilderState.graphManagerState.usableStores
453
+ .filter(filterByType(Binding))
454
+ .filter((b) => {
455
+ const elements = b.modelUnit.packageableElementIncludes.map(
456
+ (p) => p.value,
457
+ );
458
+ return elements
459
+ .filter(filterByType(Package))
460
+ .map((p) => Array.from(getDescendantsOfPackage(p)))
461
+ .flat()
462
+ .concat(elements.filter((e) => !(e instanceof Package)))
463
+ .includes(treeData.tree.class.value);
464
+ });
465
+
306
466
  const onNodeSelect = (node: QueryBuilderGraphFetchTreeNodeData): void => {
307
467
  if (node.childrenIds.length) {
308
468
  node.isOpen = !node.isOpen;
@@ -319,6 +479,24 @@ export const QueryBuilderGraphFetchTreeExplorer = observer(
319
479
 
320
480
  const removeNode = (node: QueryBuilderGraphFetchTreeNodeData): void => {
321
481
  removeNodeRecursively(treeData, node);
482
+ if (treeData.nodes.size === 0) {
483
+ graphFetchState.setSerializationState(
484
+ new GraphFetchPureSerializationState(graphFetchState),
485
+ );
486
+ }
487
+ // Remove node from external format serialization tree as well
488
+ if (
489
+ serializationState instanceof
490
+ GraphFetchExternalFormatSerializationState &&
491
+ serializationState.treeData &&
492
+ serializationState.treeData.nodes.get(node.id)
493
+ ) {
494
+ removeNodeRecursively(
495
+ serializationState.treeData,
496
+ guaranteeNonNullable(serializationState.treeData.nodes.get(node.id)),
497
+ );
498
+ updateTreeData({ ...serializationState.treeData });
499
+ }
322
500
  updateTreeData({ ...treeData });
323
501
  };
324
502
 
@@ -326,71 +504,202 @@ export const QueryBuilderGraphFetchTreeExplorer = observer(
326
504
  graphFetchState.setChecked(!graphFetchState.isChecked);
327
505
 
328
506
  const openConfigModal = (): void => {
329
- pureSerializationState.setConfigModal(true);
507
+ if (serializationState instanceof GraphFetchPureSerializationState) {
508
+ serializationState.setConfigModal(true);
509
+ }
330
510
  };
331
511
 
512
+ const onChangeSerializationType =
513
+ (implementationType: SERIALIZATION_TYPE): (() => void) =>
514
+ (): void => {
515
+ if (implementationType !== serializationState.getLabel()) {
516
+ graphFetchState.queryBuilderState.applicationStore.alertService.setActionAlertInfo(
517
+ {
518
+ message:
519
+ 'Current graph-fetch will be lost when switching to a different serialization mode. Do you still want to proceed?',
520
+ type: ActionAlertType.CAUTION,
521
+ actions: [
522
+ {
523
+ label: 'Proceed',
524
+ type: ActionAlertActionType.PROCEED_WITH_CAUTION,
525
+ handler:
526
+ graphFetchState.queryBuilderState.applicationStore.guardUnhandledError(
527
+ async () => {
528
+ switch (implementationType) {
529
+ case SERIALIZATION_TYPE.EXTERNAL_FORMAT:
530
+ if (
531
+ compatibleBindings.length > 0 &&
532
+ compatibleBindings[0]
533
+ ) {
534
+ const externalizeState =
535
+ new GraphFetchExternalFormatSerializationState(
536
+ graphFetchState,
537
+ compatibleBindings[0],
538
+ undefined,
539
+ );
540
+ graphFetchState.setGraphFetchTree(treeData);
541
+ externalizeState.setGraphFetchTree(
542
+ deepClone(treeData),
543
+ );
544
+ graphFetchState.setSerializationState(
545
+ externalizeState,
546
+ );
547
+ } else {
548
+ graphFetchState.queryBuilderState.applicationStore.notificationService.notifyWarning(
549
+ `Can't switch to external format serialization: No compatible bindings found`,
550
+ );
551
+ }
552
+ break;
553
+ case SERIALIZATION_TYPE.PURE:
554
+ default:
555
+ graphFetchState.setSerializationState(
556
+ new GraphFetchPureSerializationState(
557
+ graphFetchState,
558
+ ),
559
+ );
560
+ break;
561
+ }
562
+ },
563
+ ),
564
+ },
565
+ {
566
+ label: 'Cancel',
567
+ type: ActionAlertActionType.PROCEED,
568
+ default: true,
569
+ },
570
+ ],
571
+ },
572
+ );
573
+ }
574
+ };
575
+
332
576
  return (
333
577
  <div className="query-builder-graph-fetch-tree">
334
578
  <div className="query-builder-graph-fetch-tree__toolbar">
579
+ <div className="query-builder__fetch__structure__modes">
580
+ {Object.values(SERIALIZATION_TYPE).map((type) => (
581
+ <button
582
+ onClick={onChangeSerializationType(type)}
583
+ className={clsx('query-builder__fetch__structure__mode', {
584
+ 'query-builder__fetch__structure__mode--selected':
585
+ type === serializationState.getLabel(),
586
+ })}
587
+ key={type}
588
+ >
589
+ {prettyCONSTName(type)}
590
+ </button>
591
+ ))}
592
+ </div>
335
593
  <div className="query-builder-graph-fetch-tree__actions">
336
- <button
337
- className="query-builder-graph-fetch-tree__actions__action-btn__label"
338
- onClick={openConfigModal}
339
- title={`${
340
- pureSerializationState.config
341
- ? 'Edit pure serialization config'
342
- : 'Add pure serialization config'
343
- }`}
344
- tabIndex={-1}
345
- >
346
- <SerializeIcon className="query-builder-graph-fetch-tree__actions__action-btn__label__icon" />
347
- <div className="query-builder-graph-fetch-tree__actions__action-btn__label__title">
348
- {pureSerializationState.config ? 'Edit Config' : 'Add Config'}
594
+ {serializationState instanceof GraphFetchPureSerializationState && (
595
+ <div className="query-builder-graph-fetch-tree__actions__action">
596
+ <button
597
+ className="query-builder-graph-fetch-tree__actions__action-btn__label"
598
+ onClick={openConfigModal}
599
+ title={`${
600
+ serializationState.config
601
+ ? 'Edit pure serialization config'
602
+ : 'Add pure serialization config'
603
+ }`}
604
+ tabIndex={-1}
605
+ >
606
+ <SerializeIcon className="query-builder-graph-fetch-tree__actions__action-btn__label__icon" />
607
+ <div className="query-builder-graph-fetch-tree__actions__action-btn__label__title">
608
+ {serializationState.config ? 'Edit Config' : 'Add Config'}
609
+ </div>
610
+ </button>
349
611
  </div>
350
- </button>
351
- </div>
352
- <div
353
- className={clsx('panel__content__form__section__toggler')}
354
- onClick={toggleChecked}
355
- >
356
- <button
357
- className={clsx('panel__content__form__section__toggler__btn', {
358
- 'panel__content__form__section__toggler__btn--toggled':
359
- graphFetchState.isChecked,
360
- })}
612
+ )}
613
+ <div
614
+ className={clsx('panel__content__form__section__toggler')}
615
+ onClick={toggleChecked}
361
616
  >
362
- {graphFetchState.isChecked ? <CheckSquareIcon /> : <SquareIcon />}
363
- </button>
364
- <div className="panel__content__form__section__toggler__prompt">
365
- Check graph fetch
366
- </div>
367
- <div className="query-builder-graph-fetch-tree__toolbar__hint-icon">
368
- <InfoCircleIcon title="With this enabled, while executing, violations of constraints will reported as part of the result, rather than causing a failure" />
617
+ <button
618
+ className={clsx('panel__content__form__section__toggler__btn', {
619
+ 'panel__content__form__section__toggler__btn--toggled':
620
+ graphFetchState.isChecked,
621
+ })}
622
+ >
623
+ {graphFetchState.isChecked ? (
624
+ <CheckSquareIcon />
625
+ ) : (
626
+ <SquareIcon />
627
+ )}
628
+ </button>
629
+ <div className="panel__content__form__section__toggler__prompt">
630
+ Check graph fetch
631
+ </div>
632
+ <div className="query-builder-graph-fetch-tree__toolbar__hint-icon">
633
+ <InfoCircleIcon title="With this enabled, while executing, violations of constraints will reported as part of the result, rather than causing a failure" />
634
+ </div>
369
635
  </div>
370
636
  </div>
371
637
  </div>
372
638
  <div className="query-builder-graph-fetch-tree__container">
373
- {pureSerializationState.configModal && (
374
- <PureSerializationConfigModal
375
- pureSerializationState={pureSerializationState}
376
- graphFetchState={graphFetchState}
377
- config={
378
- pureSerializationState.config ?? new PureSerializationConfig()
379
- }
380
- />
381
- )}
382
- <TreeView
383
- components={{
384
- TreeNodeContainer: QueryBuilderGraphFetchTreeNodeContainer,
385
- }}
386
- treeData={treeData}
387
- onNodeSelect={onNodeSelect}
388
- getChildNodes={getChildNodes}
389
- innerProps={{
390
- isReadOnly,
391
- removeNode,
392
- }}
393
- />
639
+ {serializationState instanceof GraphFetchPureSerializationState &&
640
+ serializationState.configModal && (
641
+ <PureSerializationConfigModal
642
+ pureSerializationState={serializationState}
643
+ graphFetchState={graphFetchState}
644
+ config={
645
+ serializationState.config ?? new PureSerializationConfig()
646
+ }
647
+ />
648
+ )}
649
+ <ResizablePanelGroup orientation="horizontal">
650
+ <ResizablePanel>
651
+ <div className="query-builder-graph-fetch-external-format__config-group">
652
+ <div className="query-builder-graph-fetch-external-format__config-group__header">
653
+ <div className="query-builder-graph-fetch-external-format__config-group__header__title">
654
+ Graph Fetch Tree
655
+ </div>
656
+ </div>
657
+ <div className="query-builder-graph-fetch-external-format__config-group__content">
658
+ <div className="query-builder-graph-fetch-external-format__config-group__item">
659
+ <TreeView
660
+ components={{
661
+ TreeNodeContainer:
662
+ QueryBuilderGraphFetchTreeNodeContainer,
663
+ }}
664
+ className="query-builder-graph-fetch-tree__container__tree"
665
+ treeData={treeData}
666
+ onNodeSelect={onNodeSelect}
667
+ getChildNodes={getChildNodes}
668
+ innerProps={{
669
+ isReadOnly,
670
+ removeNode,
671
+ }}
672
+ />
673
+ </div>
674
+ </div>
675
+ </div>
676
+ </ResizablePanel>
677
+ <ResizablePanelSplitter />
678
+ {serializationState instanceof
679
+ GraphFetchExternalFormatSerializationState &&
680
+ serializationState.treeData && (
681
+ <ResizablePanel>
682
+ <div className="query-builder-graph-fetch-external-format__config-group">
683
+ <div className="query-builder-graph-fetch-external-format__config-group__header">
684
+ <div className="query-builder-graph-fetch-external-format__config-group__header__title">
685
+ Externalize
686
+ </div>
687
+ </div>
688
+ <div className="query-builder-graph-fetch-external-format__config-group__content">
689
+ <div className="query-builder-graph-fetch-external-format_config-group__item">
690
+ <QueryBuilderGraphFetchExternalConfig
691
+ graphFetchState={graphFetchState}
692
+ serializationState={serializationState}
693
+ serializationTreeData={serializationState.treeData}
694
+ bindings={compatibleBindings}
695
+ isReadOnly={false}
696
+ />
697
+ </div>
698
+ </div>
699
+ </div>
700
+ </ResizablePanel>
701
+ )}
702
+ </ResizablePanelGroup>
394
703
  </div>
395
704
  </div>
396
705
  );
@@ -400,10 +709,9 @@ export const QueryBuilderGraphFetchTreeExplorer = observer(
400
709
  const QueryBuilderGraphFetchTreePanel = observer(
401
710
  (props: {
402
711
  graphFetchTreeState: QueryBuilderGraphFetchTreeState;
403
-
404
- pureSerializationState: GraphFetchPureSerializationState;
712
+ serializationState: GraphFetchSerializationState;
405
713
  }) => {
406
- const { graphFetchTreeState, pureSerializationState } = props;
714
+ const { graphFetchTreeState, serializationState } = props;
407
715
  const treeData = graphFetchTreeState.treeData;
408
716
 
409
717
  // Deep/Graph Fetch Tree
@@ -415,8 +723,18 @@ const QueryBuilderGraphFetchTreePanel = observer(
415
723
  const handleDrop = useCallback(
416
724
  (item: QueryBuilderExplorerTreeDragSource): void => {
417
725
  graphFetchTreeState.addProperty(item.node, { refreshTreeData: true });
726
+ // If serializationState is GraphFetchExternalFormatSerializationState, we should add this node to
727
+ // the external format serialization tree as well
728
+ if (
729
+ serializationState instanceof
730
+ GraphFetchExternalFormatSerializationState
731
+ ) {
732
+ serializationState.addProperty(deepClone(item.node), {
733
+ refreshTreeData: true,
734
+ });
735
+ }
418
736
  },
419
- [graphFetchTreeState],
737
+ [graphFetchTreeState, serializationState],
420
738
  );
421
739
  const [{ isDragOver }, dropTargetConnector] = useDrop<
422
740
  QueryBuilderExplorerTreeDragSource,
@@ -458,7 +776,7 @@ const QueryBuilderGraphFetchTreePanel = observer(
458
776
  {treeData && !isGraphFetchTreeDataEmpty(treeData) && (
459
777
  <QueryBuilderGraphFetchTreeExplorer
460
778
  graphFetchState={graphFetchTreeState}
461
- pureSerializationState={pureSerializationState}
779
+ serializationState={serializationState}
462
780
  treeData={treeData}
463
781
  isReadOnly={false}
464
782
  updateTreeData={updateTreeData}
@@ -478,11 +796,14 @@ export const QueryBuilderGraphFetchPanel = observer(
478
796
  graphFetchTreeState.queryBuilderState.textEditorState.openModal(
479
797
  QueryBuilderTextEditorMode.TEXT,
480
798
  );
481
- if (serializationState instanceof GraphFetchPureSerializationState) {
799
+ if (
800
+ serializationState instanceof GraphFetchPureSerializationState ||
801
+ serializationState instanceof GraphFetchExternalFormatSerializationState
802
+ ) {
482
803
  return (
483
804
  <QueryBuilderGraphFetchTreePanel
484
805
  graphFetchTreeState={graphFetchTreeState}
485
- pureSerializationState={serializationState}
806
+ serializationState={serializationState}
486
807
  />
487
808
  );
488
809
  }
@@ -48,6 +48,7 @@ import {
48
48
  import type { LambdaFunctionBuilderOption } from '../../QueryBuilderValueSpecificationBuilderHelper.js';
49
49
  import { appendGraphFetch } from './QueryBuilderGraphFetchTreeValueSpecificationBuilder.js';
50
50
  import {
51
+ deepClone,
51
52
  guaranteeNonNullable,
52
53
  hashArray,
53
54
  type Hashable,
@@ -190,6 +191,7 @@ export class GraphFetchExternalFormatSerializationState extends GraphFetchSerial
190
191
  targetBinding: observable,
191
192
  treeData: observable.ref,
192
193
  serializationContentType: computed,
194
+ setGraphFetchTree: action,
193
195
  });
194
196
  this.targetBinding = targetBinding;
195
197
  this.treeData = treeData;
@@ -203,6 +205,30 @@ export class GraphFetchExternalFormatSerializationState extends GraphFetchSerial
203
205
  this.treeData = val;
204
206
  }
205
207
 
208
+ addProperty(
209
+ node: QueryBuilderExplorerTreePropertyNodeData,
210
+ options?: {
211
+ refreshTreeData?: boolean;
212
+ },
213
+ ): void {
214
+ if (!this.treeData) {
215
+ this.queryBuilderGraphFetchTreeState.queryBuilderState.applicationStore.notificationService.notifyWarning(
216
+ `Can't add property: graph-fetch tree has not been properly initialized`,
217
+ );
218
+ return;
219
+ }
220
+ addQueryBuilderPropertyNode(
221
+ this.treeData,
222
+ this.queryBuilderGraphFetchTreeState.queryBuilderState.explorerState
223
+ .nonNullableTreeData,
224
+ node,
225
+ this.queryBuilderGraphFetchTreeState.queryBuilderState,
226
+ );
227
+ if (options?.refreshTreeData) {
228
+ this.setGraphFetchTree({ ...this.treeData });
229
+ }
230
+ }
231
+
206
232
  override getLabel(): string {
207
233
  return SERIALIZATION_TYPE.EXTERNAL_FORMAT;
208
234
  }
@@ -409,6 +435,14 @@ export class QueryBuilderGraphFetchTreeState
409
435
 
410
436
  fetchProperty(node: QueryBuilderExplorerTreePropertyNodeData): void {
411
437
  this.addProperty(node, { refreshTreeData: true });
438
+ if (
439
+ this.serializationState instanceof
440
+ GraphFetchExternalFormatSerializationState
441
+ ) {
442
+ this.serializationState.addProperty(deepClone(node), {
443
+ refreshTreeData: true,
444
+ });
445
+ }
412
446
  }
413
447
 
414
448
  fetchProperties(nodes: QueryBuilderExplorerTreePropertyNodeData[]): void {
@@ -175,8 +175,8 @@ export const appendGraphFetch = (
175
175
  `Can't build graph-fetch tree expression: preceding expression is not defined`,
176
176
  );
177
177
 
178
- const seriaizationState = graphFetchTreeState.serializationState;
179
- if (seriaizationState instanceof GraphFetchPureSerializationState) {
178
+ const serializationState = graphFetchTreeState.serializationState;
179
+ if (serializationState instanceof GraphFetchPureSerializationState) {
180
180
  // build graph-fetch tree
181
181
  if (
182
182
  graphFetchTreeState.treeData &&
@@ -201,9 +201,9 @@ export const appendGraphFetch = (
201
201
  graphFetchInstance,
202
202
  ];
203
203
  serializeFunction.parametersValues = [graphFetchFunc, graphFetchInstance];
204
- if (seriaizationState.config) {
204
+ if (serializationState.config) {
205
205
  const configFunction = buildPureSerializationConfig(
206
- seriaizationState.config as unknown as Record<PropertyKey, boolean>,
206
+ serializationState.config as unknown as Record<PropertyKey, boolean>,
207
207
  graphFetchTreeState.queryBuilderState.graphManagerState.graph,
208
208
  );
209
209
  serializeFunction.parametersValues.push(configFunction);
@@ -211,18 +211,18 @@ export const appendGraphFetch = (
211
211
  lambdaFunction.expressionSequence[0] = serializeFunction;
212
212
  }
213
213
  } else if (
214
- seriaizationState instanceof GraphFetchExternalFormatSerializationState
214
+ serializationState instanceof GraphFetchExternalFormatSerializationState
215
215
  ) {
216
216
  const externalizeFunction = new SimpleFunctionExpression(
217
217
  extractElementNameFromPath(QUERY_BUILDER_SUPPORTED_FUNCTIONS.EXTERNALIZE),
218
218
  );
219
219
  const mainGraphTree = graphFetchTreeState.treeData;
220
- const externalizeTree = seriaizationState.treeData;
220
+ const externalizeGraphFetchTreeData = serializationState.treeData;
221
221
  if (
222
222
  mainGraphTree &&
223
- externalizeTree &&
223
+ externalizeGraphFetchTreeData &&
224
224
  !isGraphFetchTreeDataEmpty(mainGraphTree) &&
225
- !isGraphFetchTreeDataEmpty(externalizeTree)
225
+ !isGraphFetchTreeDataEmpty(externalizeGraphFetchTreeData)
226
226
  ) {
227
227
  // 0th param
228
228
  const graphFetchInstance = new GraphFetchTreeInstanceValue();
@@ -244,12 +244,12 @@ export const appendGraphFetch = (
244
244
  const bindingInstance = new InstanceValue(Multiplicity.ONE, undefined);
245
245
  bindingInstance.values = [
246
246
  PackageableElementExplicitReference.create(
247
- seriaizationState.targetBinding,
247
+ serializationState.targetBinding,
248
248
  ),
249
249
  ];
250
250
  // 2nd parameter
251
251
  const xtGraphFetchInstance = new GraphFetchTreeInstanceValue();
252
- xtGraphFetchInstance.values = [externalizeTree.tree];
252
+ xtGraphFetchInstance.values = [externalizeGraphFetchTreeData.tree];
253
253
  // build externalize
254
254
  externalizeFunction.parametersValues = [
255
255
  graphFetchFunc,
@@ -260,7 +260,7 @@ export const appendGraphFetch = (
260
260
  }
261
261
  } else {
262
262
  throw new UnsupportedOperationError(
263
- `Unsupported serialization state ${seriaizationState.getLabel()}`,
263
+ `Unsupported serialization state ${serializationState.getLabel()}`,
264
264
  );
265
265
  }
266
266
  // build result set modifier: i.e. preview limit