@finos/legend-application-studio 28.18.146 → 28.18.148

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 (78) hide show
  1. package/lib/components/editor/editor-group/EditorGroup.d.ts.map +1 -1
  2. package/lib/components/editor/editor-group/EditorGroup.js +10 -2
  3. package/lib/components/editor/editor-group/EditorGroup.js.map +1 -1
  4. package/lib/components/editor/editor-group/RuntimeEditor.d.ts.map +1 -1
  5. package/lib/components/editor/editor-group/RuntimeEditor.js +3 -1
  6. package/lib/components/editor/editor-group/RuntimeEditor.js.map +1 -1
  7. package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.d.ts.map +1 -1
  8. package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.js +3 -3
  9. package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.js.map +1 -1
  10. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.d.ts.map +1 -1
  11. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js +31 -7
  12. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js.map +1 -1
  13. package/lib/components/editor/editor-group/function-activator/FunctionEditor.d.ts.map +1 -1
  14. package/lib/components/editor/editor-group/function-activator/FunctionEditor.js +4 -1
  15. package/lib/components/editor/editor-group/function-activator/FunctionEditor.js.map +1 -1
  16. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.d.ts.map +1 -1
  17. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.js +21 -16
  18. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.js.map +1 -1
  19. package/lib/components/editor/ingest-definition-editor.css +1 -0
  20. package/lib/components/editor/ingest-definition-editor.css.map +1 -0
  21. package/lib/components/editor/side-bar/CreateNewElementModal.d.ts.map +1 -1
  22. package/lib/components/editor/side-bar/CreateNewElementModal.js +7 -7
  23. package/lib/components/editor/side-bar/CreateNewElementModal.js.map +1 -1
  24. package/lib/index.css +2 -2
  25. package/lib/index.css.map +1 -1
  26. package/lib/package.json +1 -1
  27. package/lib/stores/editor/GraphEditFormModeState.d.ts.map +1 -1
  28. package/lib/stores/editor/GraphEditFormModeState.js +1 -0
  29. package/lib/stores/editor/GraphEditFormModeState.js.map +1 -1
  30. package/lib/stores/editor/NewElementState.d.ts +2 -0
  31. package/lib/stores/editor/NewElementState.d.ts.map +1 -1
  32. package/lib/stores/editor/NewElementState.js +10 -2
  33. package/lib/stores/editor/NewElementState.js.map +1 -1
  34. package/lib/stores/editor/editor-state/element-editor-state/connection/ConnectionEditorState.d.ts.map +1 -1
  35. package/lib/stores/editor/editor-state/element-editor-state/connection/ConnectionEditorState.js +3 -2
  36. package/lib/stores/editor/editor-state/element-editor-state/connection/ConnectionEditorState.js.map +1 -1
  37. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts.map +1 -1
  38. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js +4 -1
  39. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js.map +1 -1
  40. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.d.ts.map +1 -1
  41. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js +7 -33
  42. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js.map +1 -1
  43. package/lib/stores/editor/panel-group/SQLPlaygroundPanelState.js +1 -1
  44. package/lib/stores/editor/panel-group/SQLPlaygroundPanelState.js.map +1 -1
  45. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts +1 -0
  46. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
  47. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js +3 -0
  48. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js.map +1 -1
  49. package/lib/stores/ingestion/IngestDeploymentServerClient.d.ts +2 -0
  50. package/lib/stores/ingestion/IngestDeploymentServerClient.d.ts.map +1 -1
  51. package/lib/stores/ingestion/IngestDeploymentServerClient.js +7 -3
  52. package/lib/stores/ingestion/IngestDeploymentServerClient.js.map +1 -1
  53. package/lib/stores/ingestion/IngestionDeploymentResponse.d.ts +1 -0
  54. package/lib/stores/ingestion/IngestionDeploymentResponse.d.ts.map +1 -1
  55. package/lib/stores/ingestion/IngestionDeploymentResponse.js +1 -0
  56. package/lib/stores/ingestion/IngestionDeploymentResponse.js.map +1 -1
  57. package/lib/stores/ingestion/IngestionManager.d.ts +1 -0
  58. package/lib/stores/ingestion/IngestionManager.d.ts.map +1 -1
  59. package/lib/stores/ingestion/IngestionManager.js +11 -1
  60. package/lib/stores/ingestion/IngestionManager.js.map +1 -1
  61. package/package.json +6 -6
  62. package/src/components/editor/editor-group/EditorGroup.tsx +19 -8
  63. package/src/components/editor/editor-group/RuntimeEditor.tsx +3 -1
  64. package/src/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.tsx +3 -2
  65. package/src/components/editor/editor-group/dataProduct/DataPoductEditor.tsx +111 -29
  66. package/src/components/editor/editor-group/function-activator/FunctionEditor.tsx +9 -2
  67. package/src/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.tsx +82 -53
  68. package/src/components/editor/side-bar/CreateNewElementModal.tsx +38 -6
  69. package/src/stores/editor/GraphEditFormModeState.ts +1 -0
  70. package/src/stores/editor/NewElementState.ts +13 -2
  71. package/src/stores/editor/editor-state/element-editor-state/connection/ConnectionEditorState.ts +3 -2
  72. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +4 -1
  73. package/src/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.ts +9 -41
  74. package/src/stores/editor/panel-group/SQLPlaygroundPanelState.ts +1 -1
  75. package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +6 -0
  76. package/src/stores/ingestion/IngestDeploymentServerClient.ts +14 -3
  77. package/src/stores/ingestion/IngestionDeploymentResponse.ts +1 -0
  78. package/src/stores/ingestion/IngestionManager.ts +18 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-application-studio",
3
- "version": "28.18.146",
3
+ "version": "28.18.148",
4
4
  "description": "Legend Studio application core",
5
5
  "keywords": [
6
6
  "legend",
@@ -47,11 +47,11 @@
47
47
  "dependencies": {
48
48
  "@finos/legend-application": "16.0.49",
49
49
  "@finos/legend-art": "7.1.103",
50
- "@finos/legend-code-editor": "2.0.83",
51
- "@finos/legend-data-cube": "0.2.16",
52
- "@finos/legend-graph": "32.1.41",
53
- "@finos/legend-lego": "2.0.89",
54
- "@finos/legend-query-builder": "4.16.52",
50
+ "@finos/legend-code-editor": "2.0.84",
51
+ "@finos/legend-data-cube": "0.2.18",
52
+ "@finos/legend-graph": "32.1.42",
53
+ "@finos/legend-lego": "2.0.90",
54
+ "@finos/legend-query-builder": "4.16.54",
55
55
  "@finos/legend-server-depot": "6.0.92",
56
56
  "@finos/legend-server-sdlc": "5.3.58",
57
57
  "@finos/legend-server-showcase": "0.2.54",
@@ -371,14 +371,25 @@ export const EditorGroup = observer(() => {
371
371
  } else if (
372
372
  currentTabState instanceof QueryConnectionEndToEndWorkflowEditorState
373
373
  ) {
374
- return (
375
- <QueryConnectionWorflowEditor
376
- connectionToQueryWorkflowState={
377
- editorStore.globalEndToEndWorkflowState
378
- .queryToConnectionWorkflowEditorState
379
- }
380
- />
381
- );
374
+ if (
375
+ editorStore.globalEndToEndWorkflowState
376
+ .queryToConnectionWorkflowEditorState.packageableConnection
377
+ ?.connectionValue.store
378
+ ) {
379
+ return (
380
+ <QueryConnectionWorflowEditor
381
+ connectionToQueryWorkflowState={
382
+ editorStore.globalEndToEndWorkflowState
383
+ .queryToConnectionWorkflowEditorState
384
+ }
385
+ />
386
+ );
387
+ } else {
388
+ editorStore.applicationStore.notificationService.notifyError(
389
+ `Cannot open query to connection workflow editor because the connection does not have a store`,
390
+ );
391
+ return null;
392
+ }
382
393
  }
383
394
  // TODO: create an editor for unsupported tab
384
395
  return null;
@@ -128,7 +128,9 @@ const getConnectionTooltipText = (
128
128
  } else if (connectionValue instanceof FlatDataConnection) {
129
129
  return `Flat-data connection \u2022 Flat-data store ${connectionValue.store.value.path}`;
130
130
  } else if (connectionValue instanceof RelationalDatabaseConnection) {
131
- return `Relational database connection \u2020 database store ${connectionValue.store.value.path}`;
131
+ return connectionValue.store
132
+ ? `Relational database connection \u2020 database store ${connectionValue.store.value.path}`
133
+ : `Relational database connection`;
132
134
  } else if (connectionValue instanceof ModelChainConnection) {
133
135
  return `Model chain connection \u2022`;
134
136
  }
@@ -1158,11 +1158,11 @@ const RelationalConnectionStoreEditor = observer(
1158
1158
  const stores =
1159
1159
  connectionValueState.editorStore.graphManagerState.graph.ownStores;
1160
1160
  const options = stores.map(buildElementOption);
1161
- const store = connection.store.value;
1161
+ const store = connection.store?.value;
1162
1162
 
1163
1163
  const selectedStore = {
1164
1164
  value: store,
1165
- label: isStoreEmpty ? noStoreLabel : store.path,
1165
+ label: isStoreEmpty ? noStoreLabel : store?.path,
1166
1166
  } as PackageableElementOption<Store>;
1167
1167
  const onStoreChange = (
1168
1168
  val: PackageableElementOption<Store> | null,
@@ -1202,6 +1202,7 @@ const RelationalConnectionStoreEditor = observer(
1202
1202
  <button
1203
1203
  className="relational-connection-editor-btn btn--dark"
1204
1204
  onClick={openDatabaseBuilder}
1205
+ disabled={Boolean(isStoreEmpty)}
1205
1206
  >
1206
1207
  Build Database
1207
1208
  </button>
@@ -17,6 +17,7 @@
17
17
  import { observer } from 'mobx-react-lite';
18
18
  import { useEditorStore } from '../../EditorStoreProvider.js';
19
19
  import {
20
+ type AccessPointGroupState,
20
21
  DataProductEditorState,
21
22
  generateUrlToDeployOnOpen,
22
23
  LakehouseAccessPointState,
@@ -48,6 +49,7 @@ import {
48
49
  MenuContent,
49
50
  MenuContentItem,
50
51
  CaretDownIcon,
52
+ WarningIcon,
51
53
  } from '@finos/legend-art';
52
54
  import React, { useRef, useState, useEffect } from 'react';
53
55
  import { filterByType } from '@finos/legend-shared';
@@ -57,10 +59,12 @@ import { useAuth } from 'react-oidc-context';
57
59
  import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
58
60
  import { CodeEditor } from '@finos/legend-lego/code-editor';
59
61
  import {
62
+ type AccessPointGroup,
60
63
  LakehouseTargetEnv,
61
64
  type LakehouseAccessPoint,
62
65
  } from '@finos/legend-graph';
63
66
  import {
67
+ accessPointGroup_setDescription,
64
68
  dataProduct_setDescription,
65
69
  dataProduct_setTitle,
66
70
  } from '../../../../stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
@@ -178,18 +182,24 @@ const NewAccessPointAccessPOint = observer(
178
182
  );
179
183
 
180
184
  interface DescriptionTextAreaProps {
181
- accessPoint: LakehouseAccessPoint;
185
+ accessPoint: LakehouseAccessPoint | AccessPointGroup;
182
186
  handleMouseOver: (event: React.MouseEvent<HTMLDivElement>) => void;
183
187
  handleMouseOut: (event: React.MouseEvent<HTMLDivElement>) => void;
188
+ className?: string;
184
189
  }
185
190
 
186
191
  const DescriptionTextArea: React.FC<DescriptionTextAreaProps> = ({
187
192
  accessPoint,
188
193
  handleMouseOver,
189
194
  handleMouseOut,
195
+ className,
190
196
  }) => {
191
197
  return (
192
- <div onMouseOver={handleMouseOver} onMouseOut={handleMouseOut}>
198
+ <div
199
+ onMouseOver={handleMouseOver}
200
+ onMouseOut={handleMouseOut}
201
+ className={clsx(className)}
202
+ >
193
203
  {accessPoint.description}
194
204
  </div>
195
205
  );
@@ -444,6 +454,91 @@ const DataProductDeploymentResponseModal = observer(
444
454
  },
445
455
  );
446
456
 
457
+ const AccessPointGroupSection = observer(
458
+ (props: { groupState: AccessPointGroupState; isReadOnly: boolean }) => {
459
+ const { groupState, isReadOnly } = props;
460
+ const [editingDescription, setEditingDescription] = useState(false);
461
+ const [isHovering, setIsHovering] = useState(false);
462
+
463
+ const handleEdit = () => setEditingDescription(true);
464
+ const handleBlur = () => {
465
+ setEditingDescription(false);
466
+ setIsHovering(false);
467
+ };
468
+ const handleMouseOver: React.MouseEventHandler<HTMLDivElement> = () => {
469
+ setIsHovering(true);
470
+ };
471
+ const handleMouseOut: React.MouseEventHandler<HTMLDivElement> = () => {
472
+ setIsHovering(false);
473
+ };
474
+
475
+ const updateGroupDescription = (val: string): void => {
476
+ accessPointGroup_setDescription(groupState.value, val);
477
+ };
478
+ return (
479
+ <div
480
+ key={groupState.value.id}
481
+ className="access-point-editor__group-container"
482
+ >
483
+ <div className="access-point-editor__group-container__title">
484
+ {groupState.value.id}
485
+ </div>
486
+ <div className="access-point-editor__group-container__description-editor">
487
+ {editingDescription ? (
488
+ <textarea
489
+ className="panel__content__form__section__input"
490
+ spellCheck={false}
491
+ value={groupState.value.description ?? ''}
492
+ onChange={(event) => updateGroupDescription(event.target.value)}
493
+ placeholder="Provide a description for this Access Point Group"
494
+ onBlur={handleBlur}
495
+ style={{
496
+ overflow: 'hidden',
497
+ resize: 'none',
498
+ padding: '0.25rem',
499
+ }}
500
+ />
501
+ ) : (
502
+ <div
503
+ onClick={handleEdit}
504
+ title="Click to edit description"
505
+ className="access-point-editor__description-container"
506
+ >
507
+ {groupState.value.description ? (
508
+ <DescriptionTextArea
509
+ accessPoint={groupState.value}
510
+ handleMouseOver={handleMouseOver}
511
+ handleMouseOut={handleMouseOut}
512
+ className="access-point-editor__group-container__description"
513
+ />
514
+ ) : (
515
+ <div
516
+ className="access-point-editor__group-container__description--warning"
517
+ onMouseOver={handleMouseOver}
518
+ onMouseOut={handleMouseOut}
519
+ >
520
+ <WarningIcon />
521
+ No description provided
522
+ </div>
523
+ )}
524
+ {isHovering && hoverIcon()}
525
+ </div>
526
+ )}
527
+ </div>
528
+ {groupState.accessPointStates
529
+ .filter(filterByType(LakehouseAccessPointState))
530
+ .map((apState) => (
531
+ <LakehouseDataProductAcccessPointEditor
532
+ key={apState.accessPoint.id}
533
+ isReadOnly={isReadOnly}
534
+ accessPointState={apState}
535
+ />
536
+ ))}
537
+ </div>
538
+ );
539
+ },
540
+ );
541
+
447
542
  export const DataProductEditor = observer(() => {
448
543
  const editorStore = useEditorStore();
449
544
  const dataProductEditorState =
@@ -565,38 +660,25 @@ export const DataProductEditor = observer(() => {
565
660
  </PanelHeaderActionItem>
566
661
  </PanelHeaderActions>
567
662
  </PanelHeader>
568
- <div style={{ overflow: 'auto' }}>
569
- <PanelContent>
663
+ <PanelContent>
664
+ <div style={{ overflow: 'auto' }}>
570
665
  {dataProductEditorState.accessPointGroupStates.map(
571
666
  (groupState) => (
572
- <div
667
+ <AccessPointGroupSection
573
668
  key={groupState.value.id}
574
- className="access-point-editor__group-container"
575
- >
576
- <div className="access-point-editor__group-container__title">
577
- <div className="panel__header__title__content">
578
- {groupState.value.id}
579
- </div>
580
- </div>
581
- {groupState.accessPointStates
582
- .filter(filterByType(LakehouseAccessPointState))
583
- .map((apState) => (
584
- <LakehouseDataProductAcccessPointEditor
585
- key={apState.accessPoint.id}
586
- isReadOnly={isReadOnly}
587
- accessPointState={apState}
588
- />
589
- ))}
590
- </div>
669
+ groupState={groupState}
670
+ isReadOnly={isReadOnly}
671
+ />
591
672
  ),
592
673
  )}
593
- {!accessPointStates.length && (
594
- <DataProductEditorSplashScreen
595
- dataProductEditorState={dataProductEditorState}
596
- />
597
- )}
598
- </PanelContent>
599
- </div>
674
+ </div>
675
+ {!accessPointStates.length && (
676
+ <DataProductEditorSplashScreen
677
+ dataProductEditorState={dataProductEditorState}
678
+ />
679
+ )}
680
+ </PanelContent>
681
+
600
682
  {dataProductEditorState.accessPointModal && (
601
683
  <NewAccessPointAccessPOint
602
684
  dataProductEditorState={dataProductEditorState}
@@ -1046,7 +1046,6 @@ const FunctionDefinitionEditor = observer(
1046
1046
  }
1047
1047
  return <BlankPanelContent>Function Did Not Run</BlankPanelContent>;
1048
1048
  };
1049
-
1050
1049
  return (
1051
1050
  <>
1052
1051
  <PanelLoadingIndicator
@@ -1154,7 +1153,15 @@ const FunctionDefinitionEditor = observer(
1154
1153
  })}
1155
1154
  >
1156
1155
  <LambdaEditor
1157
- className="function-editor__definition__lambda-editor lambda-editor--dark"
1156
+ className={clsx(
1157
+ 'function-editor__definition__lambda-editor lambda-editor--dark',
1158
+ {
1159
+ 'function-editor__definition__lambda-editor-error': Boolean(
1160
+ lambdaEditorState.parserError ??
1161
+ lambdaEditorState.compilationError,
1162
+ ),
1163
+ },
1164
+ )}
1158
1165
  disabled={
1159
1166
  lambdaEditorState.isConvertingFunctionBodyToString ||
1160
1167
  isReadOnly
@@ -41,7 +41,7 @@ import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
41
41
  import { flowResult } from 'mobx';
42
42
  import { useAuth } from 'react-oidc-context';
43
43
  import {
44
- type IngestDefinitionDeploymentResponse,
44
+ IngestDefinitionDeploymentResponse,
45
45
  IngestDefinitionValidationResponse,
46
46
  } from '../../../../stores/ingestion/IngestionDeploymentResponse.js';
47
47
 
@@ -95,75 +95,81 @@ const IngestValidationError = observer(
95
95
  },
96
96
  );
97
97
 
98
- // TODO: show full report i.e write envs etc
99
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
100
98
  const IngestDeploymentResponseModal = observer(
101
99
  (props: {
102
- state: IngestDefinitionEditorState;
100
+ closeModal: () => void;
103
101
  deploymentResponse: IngestDefinitionDeploymentResponse;
102
+ copyHandler: (text: string, successMessage: string) => void;
104
103
  }) => {
105
- const { state, deploymentResponse } = props;
106
- const applicationStore = state.editorStore.applicationStore;
107
- const closeModal = (): void =>
108
- state.setValidateAndDeployResponse(undefined);
104
+ const { closeModal, deploymentResponse, copyHandler } = props;
109
105
  const copyURN = (text: string): void => {
110
- state.editorStore.applicationStore.clipboardService
111
- .copyTextToClipboard(text)
112
- .then(() =>
113
- state.editorStore.applicationStore.notificationService.notifySuccess(
114
- 'Ingest URN copied to clipboard',
115
- undefined,
116
- 2500,
117
- ),
118
- )
119
- .catch(state.editorStore.applicationStore.alertUnhandledError);
106
+ copyHandler(text, 'Ingest URN copied to clipboard');
120
107
  };
121
108
  return (
122
109
  <Dialog
123
110
  open={true}
124
111
  classes={{
125
- root: 'editor-modal__root-container',
126
- container: 'editor-modal__container',
127
- paper: 'editor-modal__content',
112
+ root: 'ingestion-modal__root-container',
113
+ container: 'ingestion-modal__container',
114
+ paper: 'ingestion-modal__content',
128
115
  }}
129
- onClose={closeModal}
130
116
  >
131
- <Modal
132
- darkMode={
133
- !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
134
- }
135
- className="editor-modal"
136
- >
117
+ <Modal darkMode={true} className="ingestion-modal">
137
118
  <ModalHeader>
138
119
  <ModalTitle
139
- icon={<CheckCircleIcon />}
140
- title="Deployment URN"
120
+ icon={<CheckCircleIcon className="ingestion-modal--success" />}
121
+ title="Deployment Response"
141
122
  ></ModalTitle>
142
123
  </ModalHeader>
143
124
  <ModalBody>
144
- <PanelContent>
145
- <div>
146
- <div>Ingestion URN</div>
147
- <div>{deploymentResponse.ingestDefinitionUrn}</div>
148
-
149
- <div className="data-space__viewer__quickstart__tds__query-text__actions">
150
- <button
151
- className="data-space__viewer__quickstart__tds__query-text__action"
152
- tabIndex={-1}
153
- title="Copy"
154
- onClick={() => {
155
- copyURN(deploymentResponse.ingestDefinitionUrn);
156
- }}
157
- >
158
- <CopyIcon />
159
- </button>
160
- <button
161
- className="data-space__viewer__quickstart__tds__query-text__action"
162
- tabIndex={-1}
163
- ></button>
125
+ <div className="ingestion-modal__urn">
126
+ <div className="ingestion-modal__urn__info">
127
+ <div className="panel__content__form__section__header__label">
128
+ Deployment URN
129
+ </div>
130
+ <div className="ingestion-modal__urn__value">
131
+ {deploymentResponse.ingestDefinitionUrn}
164
132
  </div>
165
133
  </div>
166
- </PanelContent>
134
+ <div className="ingestion-modal__urn__copy">
135
+ <button
136
+ className="ingestion-modal__urn__copy--btn"
137
+ tabIndex={-1}
138
+ title="Copy"
139
+ onClick={() => {
140
+ copyURN(deploymentResponse.ingestDefinitionUrn);
141
+ }}
142
+ >
143
+ <CopyIcon />
144
+ </button>
145
+ </div>
146
+ </div>
147
+ <div className="ingestion-modal__write">
148
+ <div className="ingestion-modal__write__label">
149
+ Write Location
150
+ </div>
151
+ <div className="ingestion-modal__write--value">
152
+ {deploymentResponse.write_location ? (
153
+ <CodeEditor
154
+ inputValue={JSON.stringify(
155
+ deploymentResponse.write_location,
156
+ null,
157
+ 2,
158
+ )}
159
+ isReadOnly={true}
160
+ language={CODE_EDITOR_LANGUAGE.JSON}
161
+ extraEditorOptions={{
162
+ wordWrap: 'on',
163
+ }}
164
+ hideActionBar={true}
165
+ />
166
+ ) : (
167
+ <div className="ingestion-modal__write--no-value">
168
+ No write location provided
169
+ </div>
170
+ )}
171
+ </div>
172
+ </div>
167
173
  </ModalBody>
168
174
  <ModalFooter>
169
175
  <ModalFooterButton
@@ -186,7 +192,6 @@ export const IngestDefinitionEditor = observer(() => {
186
192
  );
187
193
  const ingestDef = ingestDefinitionEditorState.ingest;
188
194
  const auth = useAuth();
189
-
190
195
  const deployIngest = (): void => {
191
196
  // Trigger OAuth flow if not authenticated
192
197
  if (!auth.isAuthenticated) {
@@ -220,8 +225,32 @@ export const IngestDefinitionEditor = observer(() => {
220
225
  validateResponse={response}
221
226
  />
222
227
  );
228
+ } else if (response instanceof IngestDefinitionDeploymentResponse) {
229
+ const copyHanlder = (text: string, successMessage: string): void => {
230
+ ingestDefinitionEditorState.editorStore.applicationStore.clipboardService
231
+ .copyTextToClipboard(text)
232
+ .then(() =>
233
+ ingestDefinitionEditorState.editorStore.applicationStore.notificationService.notifySuccess(
234
+ successMessage,
235
+ undefined,
236
+ 2500,
237
+ ),
238
+ )
239
+ .catch(
240
+ ingestDefinitionEditorState.editorStore.applicationStore
241
+ .alertUnhandledError,
242
+ );
243
+ };
244
+ return (
245
+ <IngestDeploymentResponseModal
246
+ closeModal={() =>
247
+ ingestDefinitionEditorState.setValidateAndDeployResponse(undefined)
248
+ }
249
+ deploymentResponse={response}
250
+ copyHandler={copyHanlder}
251
+ />
252
+ );
223
253
  }
224
-
225
254
  return null;
226
255
  };
227
256
 
@@ -27,6 +27,7 @@ import {
27
27
  NewServiceDriver,
28
28
  CONNECTION_TYPE,
29
29
  type RuntimeOption,
30
+ NewLakehouseDataProductDriver,
30
31
  } from '../../../stores/editor/NewElementState.js';
31
32
  import { Dialog, compareLabelFn, CustomSelectorInput } from '@finos/legend-art';
32
33
  import type { EditorStore } from '../../../stores/editor/EditorStore.js';
@@ -89,7 +90,7 @@ export const getElementTypeLabel = (
89
90
  case PACKAGEABLE_ELEMENT_TYPE.TEMPORARY__LOCAL_CONNECTION:
90
91
  return 'local connection';
91
92
  case PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT:
92
- return 'lakehouse data product';
93
+ return 'Lakehouse Data Product';
93
94
  default: {
94
95
  if (type) {
95
96
  const extraElementTypeLabelGetters = editorStore.pluginManager
@@ -440,11 +441,42 @@ const NewServiceDriverEditor = observer(() => {
440
441
  });
441
442
 
442
443
  const NewLakehouseDataProductEditor = observer(() => {
443
- // const editorStore = useEditorStore();
444
- // const newProductDriver = editorStore.newElementState.getNewElementDriver(
445
- // NewLakehouseDataProductDriver,
446
- // );
447
- return null;
444
+ const editorStore = useEditorStore();
445
+ const newProductDriver = editorStore.newElementState.getNewElementDriver(
446
+ NewLakehouseDataProductDriver,
447
+ );
448
+ const handleTitleChange: React.ChangeEventHandler<HTMLInputElement> = (
449
+ event,
450
+ ) => newProductDriver.setTitle(event.target.value);
451
+ const handleDescriptionChange: React.ChangeEventHandler<HTMLInputElement> = (
452
+ event,
453
+ ) => newProductDriver.setDescription(event.target.value);
454
+ return (
455
+ <>
456
+ <div className="panel__content__form__section__header__label">Title</div>
457
+ <div className="explorer__new-element-modal__driver">
458
+ <input
459
+ className="input--dark explorer__new-element-modal__name-input"
460
+ spellCheck={false}
461
+ value={newProductDriver.title}
462
+ onChange={handleTitleChange}
463
+ placeholder={`Choose a title for this Data Product to display in Marketplace`}
464
+ />
465
+ </div>
466
+ <div className="panel__content__form__section__header__label">
467
+ Description
468
+ </div>
469
+ <div className="explorer__new-element-modal__driver">
470
+ <input
471
+ className="input--dark explorer__new-element-modal__name-input"
472
+ spellCheck={false}
473
+ value={newProductDriver.description}
474
+ onChange={handleDescriptionChange}
475
+ placeholder={`Provide a meaningful description for this Data Product`}
476
+ />
477
+ </div>
478
+ </>
479
+ );
448
480
  });
449
481
 
450
482
  const NewFileGenerationDriverEditor = observer(() => {
@@ -557,6 +557,7 @@ export class GraphEditFormModeState extends GraphEditorMode {
557
557
  *onLeave(): GeneratorFn<void> {
558
558
  this.editorStore.sqlPlaygroundState.setConnection(undefined);
559
559
  this.editorStore.tabManagerState.cacheAndClose();
560
+ this.editorStore.applicationStore.layoutService.setShowBackdrop(false);
560
561
  }
561
562
 
562
563
  *cleanupBeforeEntering(fallbackOptions?: {
@@ -109,7 +109,10 @@ import {
109
109
  } from '@finos/legend-lego/graph-editor';
110
110
  import { EmbeddedDataType } from './editor-state/ExternalFormatState.js';
111
111
  import { createEmbeddedData } from './editor-state/element-editor-state/data/EmbeddedDataState.js';
112
- import { dataProduct_setTitle } from '../graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
112
+ import {
113
+ dataProduct_setDescription,
114
+ dataProduct_setTitle,
115
+ } from '../graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
113
116
 
114
117
  export const CUSTOM_LABEL = '(custom)';
115
118
 
@@ -484,27 +487,35 @@ export class NewPackageableConnectionDriver extends NewElementDriver<Packageable
484
487
 
485
488
  export class NewLakehouseDataProductDriver extends NewElementDriver<DataProduct> {
486
489
  title: string;
490
+ description: string;
487
491
 
488
492
  constructor(editorStore: EditorStore) {
489
493
  super(editorStore);
490
494
  this.title = '';
495
+ this.description = '';
491
496
  makeObservable(this, {
492
497
  title: observable,
498
+ description: observable,
493
499
  setTitle: action,
500
+ setDescription: action,
494
501
  isValid: computed,
495
502
  });
496
503
  }
497
504
 
498
505
  override get isValid(): boolean {
499
- return true;
506
+ return Boolean(this.title && this.description);
500
507
  }
501
508
 
502
509
  setTitle(val: string) {
503
510
  this.title = val;
504
511
  }
512
+ setDescription(val: string) {
513
+ this.description = val;
514
+ }
505
515
  override createElement(name: string): DataProduct {
506
516
  const dataProduct = new DataProduct(name);
507
517
  dataProduct_setTitle(dataProduct, this.title);
518
+ dataProduct_setDescription(dataProduct, this.description);
508
519
  return dataProduct;
509
520
  }
510
521
  }
@@ -171,8 +171,9 @@ export class RelationalDatabaseConnectionValueState extends ConnectionValueState
171
171
  };
172
172
 
173
173
  get storeValidationResult(): ValidationIssue | undefined {
174
- return isStubbed_PackageableElement(this.connection.store.value)
175
- ? createValidationError(['Connection database cannot be empty'])
174
+ return !this.connection.store ||
175
+ isStubbed_PackageableElement(this.connection.store.value)
176
+ ? createValidationError(['Connection database is empty'])
176
177
  : undefined;
177
178
  }
178
179
 
@@ -373,12 +373,15 @@ export class DatabaseSchemaExplorerState {
373
373
  });
374
374
 
375
375
  this.connection = connection;
376
- this.database = guaranteeType(connection.store.value, Database);
376
+ this.database = guaranteeType(connection.store?.value, Database);
377
377
  this.editorStore = editorStore;
378
378
  this.targetDatabasePath = DEFAULT_DATABASE_PATH;
379
379
  }
380
380
 
381
381
  get isCreatingNewDatabase(): boolean {
382
+ if (!this.connection.store) {
383
+ return false;
384
+ }
382
385
  return isStubbed_PackageableElement(this.connection.store.value);
383
386
  }
384
387