@finos/legend-application-studio 28.19.59 → 28.19.60

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 (22) hide show
  1. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.d.ts +7 -1
  2. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.d.ts.map +1 -1
  3. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js +7 -7
  4. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js.map +1 -1
  5. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts.map +1 -1
  6. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js +150 -6
  7. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
  8. package/lib/index.css +1 -1
  9. package/lib/package.json +1 -1
  10. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +20 -1
  11. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts.map +1 -1
  12. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js +186 -2
  13. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
  14. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts +2 -1
  15. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
  16. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js +9 -0
  17. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js.map +1 -1
  18. package/package.json +8 -8
  19. package/src/components/editor/editor-group/data-editor/RelationElementsDataEditor.tsx +7 -7
  20. package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +310 -4
  21. package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +277 -0
  22. package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +19 -0
@@ -171,6 +171,7 @@ import {
171
171
  } from '@finos/legend-extension-dsl-data-product';
172
172
  import type { LegendStudioApplicationStore } from '../../../../stores/LegendStudioBaseStore.js';
173
173
  import type { DepotServerClient } from '@finos/legend-server-depot';
174
+ import { RelationElementEditor } from '../data-editor/RelationElementsDataEditor.js';
174
175
 
175
176
  export enum AP_GROUP_MODAL_ERRORS {
176
177
  GROUP_NAME_EMPTY = 'Group Name is empty',
@@ -231,8 +232,9 @@ const hoverIcon = () => {
231
232
  };
232
233
 
233
234
  const AccessPointTitle = observer(
234
- (props: { accessPoint: LakehouseAccessPoint }) => {
235
- const { accessPoint } = props;
235
+ (props: { accessPointState: LakehouseAccessPointState }) => {
236
+ const { accessPointState } = props;
237
+ const accessPoint = accessPointState.accessPoint;
236
238
  const [editingName, setEditingName] = useState(
237
239
  accessPoint.id === newNamePlaceholder,
238
240
  );
@@ -240,6 +242,11 @@ const AccessPointTitle = observer(
240
242
  const handleNameBlur = () => {
241
243
  if (accessPoint.id !== newNamePlaceholder) {
242
244
  setEditingName(false);
245
+ const relationElement =
246
+ accessPointState.relationElementState?.relationElement;
247
+ if (relationElement) {
248
+ relationElement.paths[0] = accessPoint.id;
249
+ }
243
250
  }
244
251
  };
245
252
  const updateAccessPointName: React.ChangeEventHandler<HTMLTextAreaElement> =
@@ -446,6 +453,212 @@ const AccessPointGenerationViewer = observer(
446
453
  },
447
454
  );
448
455
 
456
+ const SampleValuesEditorModal = observer(
457
+ (props: {
458
+ accessPointState: LakehouseAccessPointState;
459
+ isReadOnly: boolean;
460
+ }) => {
461
+ const { accessPointState, isReadOnly } = props;
462
+ const editorStore = accessPointState.state.state.editorStore;
463
+ const dataElementPath =
464
+ accessPointState.relationElementExistsinDataElementReference();
465
+ const closeModal = (): void => {
466
+ accessPointState.setShowSampleValuesModal(false);
467
+ };
468
+
469
+ const handleDeleteSampleValues = (): void => {
470
+ editorStore.applicationStore.alertService.setActionAlertInfo({
471
+ message: `Are you sure you want to delete sample values for Access Point ${accessPointState.accessPoint.id}?`,
472
+ type: ActionAlertType.CAUTION,
473
+ actions: [
474
+ {
475
+ label: 'Confirm',
476
+ type: ActionAlertActionType.PROCEED_WITH_CAUTION,
477
+ handler: (): void => {
478
+ accessPointState.deleteRelationElement();
479
+ closeModal();
480
+ },
481
+ },
482
+ {
483
+ label: 'Cancel',
484
+ type: ActionAlertActionType.PROCEED,
485
+ default: true,
486
+ },
487
+ ],
488
+ });
489
+ };
490
+
491
+ const handleNavigateToDataElement = (): void => {
492
+ if (dataElementPath) {
493
+ const dataElement =
494
+ editorStore.graphManagerState.graph.getNullableElement(
495
+ dataElementPath,
496
+ );
497
+ if (dataElement) {
498
+ editorStore.graphEditorMode.openElement(dataElement);
499
+ closeModal();
500
+ }
501
+ }
502
+ };
503
+
504
+ return (
505
+ <Dialog
506
+ open={accessPointState.showSampleValuesModal}
507
+ onClose={closeModal}
508
+ classes={{
509
+ root: 'editor-modal__root-container',
510
+ container: 'editor-modal__container',
511
+ paper: 'editor-modal__content',
512
+ }}
513
+ >
514
+ <Modal
515
+ className="editor-modal"
516
+ darkMode={
517
+ !editorStore.applicationStore.layoutService
518
+ .TEMPORARY__isLightColorThemeEnabled
519
+ }
520
+ >
521
+ <ModalHeader
522
+ title={`${accessPointState.accessPoint.title ?? accessPointState.accessPoint.id} Sample Values`}
523
+ />
524
+ <ModalBody>
525
+ <div
526
+ style={{
527
+ padding: 0,
528
+ minHeight: 'auto',
529
+ }}
530
+ >
531
+ {dataElementPath !== undefined ? (
532
+ <div
533
+ style={{
534
+ padding: '1.5rem',
535
+ display: 'flex',
536
+ alignItems: 'center',
537
+ justifyContent: 'center',
538
+ gap: '1rem',
539
+ }}
540
+ >
541
+ <span
542
+ style={{
543
+ color: 'var(--color-light-grey-200)',
544
+ whiteSpace: 'nowrap',
545
+ fontSize: '1.3rem',
546
+ fontWeight: 600,
547
+ }}
548
+ >
549
+ Sample Values already in Data Element
550
+ </span>
551
+ <div
552
+ style={{
553
+ display: 'flex',
554
+ alignItems: 'center',
555
+ gap: '0.5rem',
556
+ padding: '0.5rem 1rem',
557
+ background: 'var(--color-dark-grey-100)',
558
+ border: '1px solid var(--color-dark-grey-300)',
559
+ borderRadius: '0.2rem',
560
+ }}
561
+ >
562
+ <span
563
+ style={{
564
+ fontSize: '1.3rem',
565
+ fontWeight: 600,
566
+ color: 'var(--color-light-grey-200)',
567
+ }}
568
+ >
569
+ {dataElementPath}
570
+ </span>
571
+ <button
572
+ className="btn--sm btn--dark"
573
+ onClick={handleNavigateToDataElement}
574
+ tabIndex={-1}
575
+ title="Navigate to data element"
576
+ style={{
577
+ padding: '0.3rem 0.5rem',
578
+ display: 'flex',
579
+ alignItems: 'center',
580
+ }}
581
+ >
582
+ <LongArrowRightIcon />
583
+ </button>
584
+ </div>
585
+ </div>
586
+ ) : (
587
+ <>
588
+ <div
589
+ style={{
590
+ color: 'var(--color-orange-200)',
591
+ fontWeight: 'bold',
592
+ fontSize: '14px',
593
+ padding: '0.5rem',
594
+ marginBottom: '1rem',
595
+ textAlign: 'center',
596
+ backgroundColor: 'var(--color-orange-50)',
597
+ border: '2px solid var(--color-orange-200)',
598
+ borderRadius: '4px',
599
+ }}
600
+ >
601
+ DO NOT ADD SENSITIVE DATA
602
+ </div>
603
+ {accessPointState.relationElementState && (
604
+ <Tooltip
605
+ title={
606
+ accessPointState.getRelationElementMismatchMessage() ??
607
+ ''
608
+ }
609
+ arrow={true}
610
+ placement="top"
611
+ disableHoverListener={
612
+ !accessPointState.hasRelationElementMismatch
613
+ }
614
+ >
615
+ <div
616
+ style={{
617
+ border: accessPointState.hasRelationElementMismatch
618
+ ? '2px solid var(--color-red-300)'
619
+ : 'none',
620
+ borderRadius: '4px',
621
+ padding: accessPointState.hasRelationElementMismatch
622
+ ? '0.5rem'
623
+ : '0',
624
+ }}
625
+ >
626
+ <RelationElementEditor
627
+ relationElementState={
628
+ accessPointState.relationElementState
629
+ }
630
+ isReadOnly={isReadOnly}
631
+ />
632
+ </div>
633
+ </Tooltip>
634
+ )}
635
+ </>
636
+ )}
637
+ </div>
638
+ </ModalBody>
639
+ <ModalFooter>
640
+ {dataElementPath === undefined && (
641
+ <ModalFooterButton
642
+ title="Delete sample values"
643
+ onClick={handleDeleteSampleValues}
644
+ text="Delete"
645
+ type="secondary"
646
+ disabled={isReadOnly}
647
+ />
648
+ )}
649
+ <ModalFooterButton
650
+ title="Close sample values editor"
651
+ onClick={closeModal}
652
+ text="Close"
653
+ type="secondary"
654
+ />
655
+ </ModalFooter>
656
+ </Modal>
657
+ </Dialog>
658
+ );
659
+ },
660
+ );
661
+
449
662
  export const LakehouseDataProductAccessPointEditor = observer(
450
663
  (props: {
451
664
  accessPointState: LakehouseAccessPointState;
@@ -465,6 +678,12 @@ export const LakehouseDataProductAccessPointEditor = observer(
465
678
  const [isHoveringTitle, setIsHoveringTitle] = useState(false);
466
679
  const ref = useRef<HTMLDivElement>(null);
467
680
 
681
+ const handleEditorBlur = useCallback(() => {
682
+ flowResult(lambdaEditorState.updateLambdaRelationColumns()).catch(
683
+ editorStore.applicationStore.alertUnhandledError,
684
+ );
685
+ }, [lambdaEditorState, editorStore.applicationStore]);
686
+
468
687
  const handleDescriptionEdit = () => setEditingDescription(true);
469
688
  const handleDescriptionBlur = () => {
470
689
  setEditingDescription(false);
@@ -588,7 +807,7 @@ export const LakehouseDataProductAccessPointEditor = observer(
588
807
  />
589
808
  <div style={{ flex: 1 }}>
590
809
  <div className="access-point-editor__metadata">
591
- <AccessPointTitle accessPoint={accessPoint} />
810
+ <AccessPointTitle accessPointState={accessPointState} />
592
811
  <div className="access-point-editor__info">
593
812
  <div className="access-point-editor__reproducible">
594
813
  <Checkbox
@@ -623,6 +842,85 @@ export const LakehouseDataProductAccessPointEditor = observer(
623
842
  <div>Reproducible</div>
624
843
  </Tooltip>
625
844
  </div>
845
+ {accessPointState.relationElementExistsinDataElementReference() !==
846
+ undefined ? (
847
+ <button
848
+ className="access-point-editor__sample-values-btn"
849
+ onClick={() =>
850
+ accessPointState.setShowSampleValuesModal(true)
851
+ }
852
+ disabled={props.isReadOnly}
853
+ title="Edit sample values"
854
+ style={{
855
+ border: '1px solid var(--color-blue-200)',
856
+ borderRadius: '4px',
857
+ padding: '0.5rem 0.75rem',
858
+ background: 'var(--color-blue-200)',
859
+ cursor: props.isReadOnly ? 'not-allowed' : 'pointer',
860
+ display: 'flex',
861
+ alignItems: 'center',
862
+ gap: '0.5rem',
863
+ color: 'white',
864
+ fontSize: '1.2rem',
865
+ whiteSpace: 'nowrap',
866
+ }}
867
+ >
868
+ <PencilEditIcon />
869
+ <span>Sample Values</span>
870
+ </button>
871
+ ) : accessPointState.relationElementState !== undefined ? (
872
+ <button
873
+ className="access-point-editor__sample-values-btn"
874
+ onClick={() =>
875
+ accessPointState.setShowSampleValuesModal(true)
876
+ }
877
+ disabled={props.isReadOnly}
878
+ title="Edit sample values"
879
+ style={{
880
+ border: accessPointState.hasRelationElementMismatch
881
+ ? '2px solid var(--color-red-300)'
882
+ : '1px solid var(--color-blue-200)',
883
+ borderRadius: '4px',
884
+ padding: '0.5rem 0.75rem',
885
+ background: 'var(--color-blue-200)',
886
+ cursor: props.isReadOnly ? 'not-allowed' : 'pointer',
887
+ display: 'flex',
888
+ alignItems: 'center',
889
+ gap: '0.5rem',
890
+ color: 'white',
891
+ fontSize: '1.2rem',
892
+ whiteSpace: 'nowrap',
893
+ }}
894
+ >
895
+ <PencilEditIcon />
896
+ <span>Sample Values</span>
897
+ </button>
898
+ ) : (
899
+ <button
900
+ className="access-point-editor__sample-values-btn"
901
+ onClick={() => {
902
+ accessPointState.createAndaddRelationElement();
903
+ }}
904
+ disabled={props.isReadOnly}
905
+ title="Add sample values"
906
+ style={{
907
+ border: '1px solid var(--color-blue-200)',
908
+ borderRadius: '4px',
909
+ padding: '0.5rem 0.75rem',
910
+ background: 'var(--color-blue-200)',
911
+ cursor: props.isReadOnly ? 'not-allowed' : 'pointer',
912
+ display: 'flex',
913
+ alignItems: 'center',
914
+ gap: '0.5rem',
915
+ color: 'white',
916
+ fontSize: '1.2rem',
917
+ whiteSpace: 'nowrap',
918
+ }}
919
+ >
920
+ <PlusIcon />
921
+ <span>Sample Values</span>
922
+ </button>
923
+ )}
626
924
  {editorStore.applicationStore.config.options
627
925
  .dataProductConfig && (
628
926
  <AccessPointClassification
@@ -725,10 +1023,11 @@ export const LakehouseDataProductAccessPointEditor = observer(
725
1023
  style={{
726
1024
  background: 'var(--color-blue-200)',
727
1025
  borderRadius: '4px',
728
- marginRight: '0.5rem',
1026
+ marginRight: '1.5rem',
729
1027
  padding: '0.25rem 0.5rem',
730
1028
  display: 'flex',
731
1029
  alignItems: 'center',
1030
+ color: 'white',
732
1031
  }}
733
1032
  >
734
1033
  <ListIcon />
@@ -833,6 +1132,7 @@ export const LakehouseDataProductAccessPointEditor = observer(
833
1132
  }
834
1133
  lambdaEditorState={lambdaEditorState}
835
1134
  forceBackdrop={Boolean(lambdaEditorState.parserError)}
1135
+ onEditorBlur={handleEditorBlur}
836
1136
  />
837
1137
  </div>
838
1138
  </div>
@@ -856,6 +1156,12 @@ export const LakehouseDataProductAccessPointEditor = observer(
856
1156
  generationOutput={accessPointState.artifactGenerationContent}
857
1157
  />
858
1158
  )}
1159
+ {accessPointState.showSampleValuesModal && (
1160
+ <SampleValuesEditorModal
1161
+ accessPointState={accessPointState}
1162
+ isReadOnly={props.isReadOnly}
1163
+ />
1164
+ )}
859
1165
  </div>
860
1166
  </PanelDnDEntry>
861
1167
  );