@finos/legend-application-studio 28.18.136 → 28.18.138

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 (33) hide show
  1. package/lib/__lib__/LegendStudioEvent.d.ts +2 -1
  2. package/lib/__lib__/LegendStudioEvent.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioEvent.js +2 -0
  4. package/lib/__lib__/LegendStudioEvent.js.map +1 -1
  5. package/lib/components/LegendStudioWebApplication.d.ts.map +1 -1
  6. package/lib/components/LegendStudioWebApplication.js +13 -29
  7. package/lib/components/LegendStudioWebApplication.js.map +1 -1
  8. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.d.ts.map +1 -1
  9. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js +43 -8
  10. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js.map +1 -1
  11. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.d.ts.map +1 -1
  12. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.js +34 -15
  13. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.js.map +1 -1
  14. package/lib/components/editor/side-bar/CreateNewElementModal.d.ts.map +1 -1
  15. package/lib/components/editor/side-bar/CreateNewElementModal.js +6 -5
  16. package/lib/components/editor/side-bar/CreateNewElementModal.js.map +1 -1
  17. package/lib/index.css +2 -2
  18. package/lib/index.css.map +1 -1
  19. package/lib/package.json +1 -1
  20. package/lib/stores/editor/NewElementState.js +1 -1
  21. package/lib/stores/editor/NewElementState.js.map +1 -1
  22. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.d.ts +4 -3
  23. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.d.ts.map +1 -1
  24. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js +41 -10
  25. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js.map +1 -1
  26. package/package.json +6 -6
  27. package/src/__lib__/LegendStudioEvent.ts +3 -0
  28. package/src/components/LegendStudioWebApplication.tsx +31 -38
  29. package/src/components/editor/editor-group/dataProduct/DataPoductEditor.tsx +143 -20
  30. package/src/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.tsx +101 -34
  31. package/src/components/editor/side-bar/CreateNewElementModal.tsx +5 -22
  32. package/src/stores/editor/NewElementState.ts +1 -1
  33. package/src/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.ts +72 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-application-studio",
3
- "version": "28.18.136",
3
+ "version": "28.18.138",
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.48",
49
49
  "@finos/legend-art": "7.1.102",
50
- "@finos/legend-code-editor": "2.0.78",
51
- "@finos/legend-data-cube": "0.2.10",
52
- "@finos/legend-graph": "32.1.36",
53
- "@finos/legend-lego": "2.0.83",
54
- "@finos/legend-query-builder": "4.16.44",
50
+ "@finos/legend-code-editor": "2.0.80",
51
+ "@finos/legend-data-cube": "0.2.12",
52
+ "@finos/legend-graph": "32.1.38",
53
+ "@finos/legend-lego": "2.0.85",
54
+ "@finos/legend-query-builder": "4.16.46",
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",
@@ -77,4 +77,7 @@ export enum LEGEND_STUDIO_APP_EVENT {
77
77
  TEXT_MODE_ACTION_KEYBOARD_SHORTCUT_GO_TO_DEFINITION__LAUNCH = 'editor.text-mode.action.keyboard.shortcut.go-to-element.launch',
78
78
  TEXT_MODE_ACTION_KEYBOARD_SHORTCUT_GO_TO_DEFINITION__ERROR = 'editor.text-mode.action.keyboard.shortcut.go-to-element.error',
79
79
  TEXT_MODE_ACTION_KEYBOARD_SHORTCUT_GO_TO_DEFINITION__SUCCESS = 'editor.text-mode.action.keyboard.shortcut.go-to-element.success',
80
+
81
+ // Ingestion
82
+ INGESTION_DEPLOY_SUCCESS_URN = 'editor.ingestion.deployment.success.urn',
80
83
  }
@@ -20,7 +20,13 @@ import { Editor } from './editor/Editor.js';
20
20
  import { ProjectReviewer } from './project-reviewer/ProjectReviewer.js';
21
21
  import { ProjectViewer } from './project-view/ProjectViewer.js';
22
22
  import { observer } from 'mobx-react-lite';
23
- import { clsx, GhostIcon, MarkdownTextViewer } from '@finos/legend-art';
23
+ import {
24
+ clsx,
25
+ CubesLoadingIndicator,
26
+ CubesLoadingIndicatorIcon,
27
+ GhostIcon,
28
+ MarkdownTextViewer,
29
+ } from '@finos/legend-art';
24
30
  import {
25
31
  LEGEND_STUDIO_ROUTE_PATTERN,
26
32
  LEGEND_STUDIO_SDLC_BYPASSED_ROUTE_PATTERN,
@@ -44,11 +50,10 @@ import { PureCompatibilityTestManager } from './pct/PureCompatibilityTest.js';
44
50
  import { ShowcaseViewer } from './showcase/ShowcaseViewer.js';
45
51
  import {
46
52
  AuthProvider,
47
- useAuth,
53
+ withAuthenticationRequired,
48
54
  type AuthProviderProps,
49
55
  } from 'react-oidc-context';
50
56
  import type { User } from 'oidc-client-ts';
51
- import { assertErrorThrown } from '@finos/legend-shared';
52
57
 
53
58
  const NotFoundPage = observer(() => {
54
59
  const applicationStore = useApplicationStore();
@@ -293,33 +298,6 @@ export const LegendStudioWebApplicationRouter = observer(() => {
293
298
  const LegendStudioWebProvider: React.FC<{
294
299
  baseUrl: string;
295
300
  }> = ({ baseUrl }) => {
296
- const applicationStore = useLegendStudioApplicationStore();
297
-
298
- const enableOauthFlow = applicationStore.config.options.enableOauthFlow;
299
- const auth = useAuth();
300
-
301
- useEffect(() => {
302
- const tryLogin = async () => {
303
- if (enableOauthFlow) {
304
- try {
305
- const user = auth.user;
306
- if ((!user || user.expired) && !auth.isLoading) {
307
- await auth.signinRedirect({
308
- state: window.location.pathname + window.location.search,
309
- });
310
- }
311
- } catch (error) {
312
- assertErrorThrown(error);
313
- applicationStore.logUnhandledError(error);
314
- }
315
- }
316
- };
317
-
318
- tryLogin().catch((error) => {
319
- assertErrorThrown(error);
320
- });
321
- }, [enableOauthFlow, applicationStore, auth]);
322
-
323
301
  return (
324
302
  <BrowserEnvironmentProvider baseUrl={baseUrl}>
325
303
  <LegendStudioFrameworkProvider>
@@ -329,6 +307,20 @@ const LegendStudioWebProvider: React.FC<{
329
307
  );
330
308
  };
331
309
 
310
+ const AuthenticatedLegendStudioWebProvider = withAuthenticationRequired(
311
+ LegendStudioWebProvider,
312
+ {
313
+ OnRedirecting: () => (
314
+ <CubesLoadingIndicator isLoading={true}>
315
+ <CubesLoadingIndicatorIcon />
316
+ </CubesLoadingIndicator>
317
+ ),
318
+ signinRedirectArgs: {
319
+ state: `${window.location.pathname}${window.location.search}`,
320
+ },
321
+ },
322
+ );
323
+
332
324
  export const LegendStudioWebApplication = observer(
333
325
  (props: { baseUrl: string }) => {
334
326
  const { baseUrl } = props;
@@ -337,6 +329,7 @@ export const LegendStudioWebApplication = observer(
337
329
  const oidcConfig =
338
330
  applicationStore.config.options.ingestDeploymentConfig?.deployment
339
331
  .oidcConfig;
332
+ const enableOauthFlow = applicationStore.config.options.enableOauthFlow;
340
333
  if (oidcConfig) {
341
334
  const onSigninCallback = (_user: User | undefined) => {
342
335
  window.location.href = (_user?.state as string | undefined) ?? '/';
@@ -346,10 +339,16 @@ export const LegendStudioWebApplication = observer(
346
339
  ...oidcConfig.authProviderProps,
347
340
  redirect_uri: `${window.location.origin}${oidcConfig.redirectPath}`,
348
341
  silent_redirect_uri: `${window.location.origin}${oidcConfig.silentRedirectPath}`,
349
- automaticSilentRenew: true,
350
342
  onSigninCallback,
351
343
  };
352
344
 
345
+ if (enableOauthFlow) {
346
+ return (
347
+ <AuthProvider {...mergedOIDCConfig}>
348
+ <AuthenticatedLegendStudioWebProvider baseUrl={baseUrl} />
349
+ </AuthProvider>
350
+ );
351
+ }
353
352
  return (
354
353
  <AuthProvider {...mergedOIDCConfig}>
355
354
  <LegendStudioWebProvider baseUrl={baseUrl} />
@@ -357,12 +356,6 @@ export const LegendStudioWebApplication = observer(
357
356
  );
358
357
  }
359
358
 
360
- return (
361
- <BrowserEnvironmentProvider baseUrl={baseUrl}>
362
- <LegendStudioFrameworkProvider>
363
- <LegendStudioWebApplicationRouter />
364
- </LegendStudioFrameworkProvider>
365
- </BrowserEnvironmentProvider>
366
- );
359
+ return <LegendStudioWebProvider baseUrl={baseUrl} />;
367
360
  },
368
361
  );
@@ -42,14 +42,17 @@ import {
42
42
  ModalBody,
43
43
  ModalFooter,
44
44
  ModalFooterButton,
45
+ PencilEditIcon,
46
+ PanelFormTextField,
45
47
  } from '@finos/legend-art';
46
- import { useRef, useState, useEffect } from 'react';
48
+ import React, { useRef, useState, useEffect } from 'react';
47
49
  import { filterByType } from '@finos/legend-shared';
48
50
  import { InlineLambdaEditor } from '@finos/legend-query-builder';
49
- import { flowResult } from 'mobx';
51
+ import { action, flowResult } from 'mobx';
50
52
  import { useAuth } from 'react-oidc-context';
51
53
  import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
52
54
  import { CodeEditor } from '@finos/legend-lego/code-editor';
55
+ import type { LakehouseAccessPoint } from '@finos/legend-graph';
53
56
 
54
57
  const NewAccessPointAccessPOint = observer(
55
58
  (props: { dataProductEditorState: DataProductEditorState }) => {
@@ -163,6 +166,32 @@ const NewAccessPointAccessPOint = observer(
163
166
  },
164
167
  );
165
168
 
169
+ interface DescriptionTextAreaProps {
170
+ accessPoint: LakehouseAccessPoint;
171
+ handleMouseOver: (event: React.MouseEvent<HTMLDivElement>) => void;
172
+ handleMouseOut: (event: React.MouseEvent<HTMLDivElement>) => void;
173
+ }
174
+
175
+ const DescriptionTextArea: React.FC<DescriptionTextAreaProps> = ({
176
+ accessPoint,
177
+ handleMouseOver,
178
+ handleMouseOut,
179
+ }) => {
180
+ return (
181
+ <div onMouseOver={handleMouseOver} onMouseOut={handleMouseOut}>
182
+ {accessPoint.description}
183
+ </div>
184
+ );
185
+ };
186
+
187
+ const hoverIcon = () => {
188
+ return (
189
+ <div>
190
+ <PencilEditIcon />
191
+ </div>
192
+ );
193
+ };
194
+
166
195
  export const LakehouseDataProductAcccessPointEditor = observer(
167
196
  (props: {
168
197
  accessPointState: LakehouseAccessPointState;
@@ -175,6 +204,28 @@ export const LakehouseDataProductAcccessPointEditor = observer(
175
204
  const propertyHasParserError = productEditorState.accessPointStates
176
205
  .filter(filterByType(LakehouseAccessPointState))
177
206
  .find((pm) => pm.lambdaState.parserError);
207
+ const [editingDescription, setEditingDescription] = useState(false);
208
+ const [isHovering, setIsHovering] = useState(false);
209
+
210
+ const handleEdit = () => setEditingDescription(true);
211
+ const handleBlur = () => {
212
+ setEditingDescription(false);
213
+ setIsHovering(false);
214
+ };
215
+
216
+ const handleMouseOver: React.MouseEventHandler<HTMLDivElement> = () => {
217
+ setIsHovering(true);
218
+ };
219
+ const handleMouseOut: React.MouseEventHandler<HTMLDivElement> = () => {
220
+ setIsHovering(false);
221
+ };
222
+
223
+ const updateAccessPointDescription: React.ChangeEventHandler<
224
+ HTMLTextAreaElement
225
+ > = (event) => {
226
+ action((accessPoint.description = event.target.value));
227
+ };
228
+
178
229
  return (
179
230
  <div
180
231
  className={clsx('access-point-editor', {
@@ -187,6 +238,34 @@ export const LakehouseDataProductAcccessPointEditor = observer(
187
238
  {accessPoint.id}
188
239
  </div>
189
240
  </div>
241
+ {editingDescription ? (
242
+ <textarea
243
+ className="panel__content__form__section__input"
244
+ spellCheck={false}
245
+ value={accessPoint.description ?? ''}
246
+ onChange={updateAccessPointDescription}
247
+ placeholder="Access Point description"
248
+ onBlur={handleBlur}
249
+ style={{
250
+ overflow: 'hidden',
251
+ resize: 'none',
252
+ padding: '0.25rem',
253
+ }}
254
+ />
255
+ ) : (
256
+ <div
257
+ onClick={handleEdit}
258
+ title="Click to edit description"
259
+ className="access-point-editor__description-container"
260
+ >
261
+ <DescriptionTextArea
262
+ accessPoint={accessPoint}
263
+ handleMouseOver={handleMouseOver}
264
+ handleMouseOut={handleMouseOut}
265
+ />
266
+ {isHovering && hoverIcon()}
267
+ </div>
268
+ )}
190
269
  <div className="access-point-editor__info">
191
270
  <div
192
271
  className={clsx('access-point-editor__type')}
@@ -287,7 +366,7 @@ const DataProductDeploymentResponseModal = observer(
287
366
  className="editor-modal"
288
367
  >
289
368
  <ModalHeader>
290
- <ModalTitle title="Validation Error" />
369
+ <ModalTitle title="Data Product Deployment Response" />
291
370
  </ModalHeader>
292
371
  <ModalBody>
293
372
  <PanelContent>
@@ -352,6 +431,19 @@ export const DataProductEditor = observer(() => {
352
431
  }
353
432
  };
354
433
 
434
+ const updateDataProductTitle = action((val: string | undefined): void => {
435
+ if (val === undefined) {
436
+ return;
437
+ }
438
+ product.name = val;
439
+ });
440
+
441
+ const updateDataProductDescription = action(
442
+ (val: string | undefined): void => {
443
+ product.description = val;
444
+ },
445
+ );
446
+
355
447
  useEffect(() => {
356
448
  flowResult(dataProductEditorState.convertAccessPointsFuncObjects()).catch(
357
449
  dataProductEditorState.editorStore.applicationStore.alertUnhandledError,
@@ -381,7 +473,6 @@ export const DataProductEditor = observer(() => {
381
473
  </div>
382
474
  )}
383
475
  <div className="panel__header__title__label">data product</div>
384
- <div className="panel__header__title__content">{product.name}</div>
385
476
  </div>
386
477
  <PanelHeaderActions>
387
478
  <div className="btn__dropdown-combo btn__dropdown-combo--primary">
@@ -398,10 +489,26 @@ export const DataProductEditor = observer(() => {
398
489
  </div>
399
490
  </PanelHeaderActions>
400
491
  </div>
492
+ <div className="panel" style={{ padding: '1rem' }}>
493
+ <PanelFormTextField
494
+ name="Title"
495
+ value={product.name}
496
+ prompt="Provide a title for this Lakehouse Data Product."
497
+ update={updateDataProductTitle}
498
+ placeholder="Enter title"
499
+ />
500
+ <PanelFormTextField
501
+ name="Description"
502
+ value={product.description}
503
+ prompt="Provide a description for this Lakehouse Data Product."
504
+ update={updateDataProductDescription}
505
+ placeholder="Enter description"
506
+ />
507
+ </div>
401
508
  <div className="panel">
402
509
  <PanelHeader>
403
510
  <div className="panel__header__title">
404
- <div className="panel__header__title__content">ACCESS POINTS</div>
511
+ <div className="panel__header__title__label">access points</div>
405
512
  </div>
406
513
  <PanelHeaderActions>
407
514
  <PanelHeaderActionItem
@@ -414,22 +521,38 @@ export const DataProductEditor = observer(() => {
414
521
  </PanelHeaderActionItem>
415
522
  </PanelHeaderActions>
416
523
  </PanelHeader>
417
- <PanelContent>
418
- {accessPointStates
419
- .filter(filterByType(LakehouseAccessPointState))
420
- .map((apState) => (
421
- <LakehouseDataProductAcccessPointEditor
422
- key={apState.accessPoint.id}
423
- isReadOnly={isReadOnly}
424
- accessPointState={apState}
524
+ <div style={{ overflow: 'auto' }}>
525
+ <PanelContent>
526
+ {dataProductEditorState.accessPointGroupStates.map(
527
+ (groupState) => (
528
+ <div
529
+ key={groupState.value.id}
530
+ className="access-point-editor__group-container"
531
+ >
532
+ <div className="access-point-editor__group-container__title">
533
+ <div className="panel__header__title__content">
534
+ {groupState.value.id}
535
+ </div>
536
+ </div>
537
+ {groupState.accessPointStates
538
+ .filter(filterByType(LakehouseAccessPointState))
539
+ .map((apState) => (
540
+ <LakehouseDataProductAcccessPointEditor
541
+ key={apState.accessPoint.id}
542
+ isReadOnly={isReadOnly}
543
+ accessPointState={apState}
544
+ />
545
+ ))}
546
+ </div>
547
+ ),
548
+ )}
549
+ {!accessPointStates.length && (
550
+ <DataProductEditorSplashScreen
551
+ dataProductEditorState={dataProductEditorState}
425
552
  />
426
- ))}
427
- {!accessPointStates.length && (
428
- <DataProductEditorSplashScreen
429
- dataProductEditorState={dataProductEditorState}
430
- />
431
- )}
432
- </PanelContent>
553
+ )}
554
+ </PanelContent>
555
+ </div>
433
556
  {dataProductEditorState.accessPointModal && (
434
557
  <NewAccessPointAccessPOint
435
558
  dataProductEditorState={dataProductEditorState}
@@ -17,6 +17,8 @@
17
17
  import { observer } from 'mobx-react-lite';
18
18
  import { useEditorStore } from '../../EditorStoreProvider.js';
19
19
  import {
20
+ CheckCircleIcon,
21
+ CopyIcon,
20
22
  Dialog,
21
23
  Modal,
22
24
  ModalBody,
@@ -34,50 +36,91 @@ import {
34
36
  IngestDefinitionEditorState,
35
37
  } from '../../../../stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js';
36
38
  import { CodeEditor } from '@finos/legend-lego/code-editor';
37
- import { useEffect } from 'react';
39
+ import React, { useEffect } from 'react';
38
40
  import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
39
41
  import { flowResult } from 'mobx';
40
42
  import { useAuth } from 'react-oidc-context';
43
+ import {
44
+ type IngestDefinitionDeploymentResponse,
45
+ IngestDefinitionValidationResponse,
46
+ } from '../../../../stores/ingestion/IngestionDeploymentResponse.js';
41
47
 
42
- const IngestDepoymentModal = observer(
43
- (props: { state: IngestDefinitionEditorState }) => {
44
- const { state } = props;
48
+ const IngestValidationError = observer(
49
+ (props: {
50
+ state: IngestDefinitionEditorState;
51
+ validateResponse: IngestDefinitionValidationResponse;
52
+ }) => {
53
+ const { state, validateResponse } = props;
45
54
  const applicationStore = state.editorStore.applicationStore;
55
+ const closeModal = (): void =>
56
+ state.setValidateAndDeployResponse(undefined);
46
57
  return (
47
58
  <Dialog
48
- open={state.deploymentState.isInProgress}
49
- classes={{ container: 'search-modal__container' }}
59
+ open={true}
60
+ classes={{
61
+ root: 'editor-modal__root-container',
62
+ container: 'editor-modal__container',
63
+ paper: 'editor-modal__content',
64
+ }}
65
+ onClose={closeModal}
50
66
  >
51
67
  <Modal
52
68
  darkMode={
53
69
  !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
54
70
  }
55
- className="database-builder"
71
+ className="editor-modal"
56
72
  >
57
73
  <ModalHeader>
58
- <ModalTitle title="Deploy Ingestion" />
74
+ <ModalTitle title={'Validation Error'} />
59
75
  </ModalHeader>
60
76
  <ModalBody>
61
- <div>{state.deploymentState.message}</div>
77
+ <PanelContent>
78
+ <CodeEditor
79
+ inputValue={JSON.stringify(validateResponse, null, 2)}
80
+ isReadOnly={true}
81
+ language={CODE_EDITOR_LANGUAGE.JSON}
82
+ />
83
+ </PanelContent>
62
84
  </ModalBody>
85
+ <ModalFooter>
86
+ <ModalFooterButton
87
+ onClick={closeModal}
88
+ text="Close"
89
+ type="secondary"
90
+ />
91
+ </ModalFooter>
63
92
  </Modal>
64
93
  </Dialog>
65
94
  );
66
95
  },
67
96
  );
68
97
 
69
- const IngestValidationError = observer(
70
- (props: { state: IngestDefinitionEditorState }) => {
71
- const { state } = props;
98
+ // TODO: show full report i.e write envs etc
99
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
100
+ const IngestDeploymentResponseModal = observer(
101
+ (props: {
102
+ state: IngestDefinitionEditorState;
103
+ deploymentResponse: IngestDefinitionDeploymentResponse;
104
+ }) => {
105
+ const { state, deploymentResponse } = props;
72
106
  const applicationStore = state.editorStore.applicationStore;
73
- const validationError = state.validationError;
74
- if (!validationError) {
75
- return null;
76
- }
77
- const closeModal = (): void => state.setValError(undefined);
107
+ const closeModal = (): void =>
108
+ state.setValidateAndDeployResponse(undefined);
109
+ 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);
120
+ };
78
121
  return (
79
122
  <Dialog
80
- open={Boolean(state.validationError)}
123
+ open={true}
81
124
  classes={{
82
125
  root: 'editor-modal__root-container',
83
126
  container: 'editor-modal__container',
@@ -92,19 +135,34 @@ const IngestValidationError = observer(
92
135
  className="editor-modal"
93
136
  >
94
137
  <ModalHeader>
95
- <ModalTitle title="Validation Error" />
138
+ <ModalTitle
139
+ icon={<CheckCircleIcon />}
140
+ title="Deployment URN"
141
+ ></ModalTitle>
96
142
  </ModalHeader>
97
143
  <ModalBody>
98
144
  <PanelContent>
99
- <CodeEditor
100
- inputValue={JSON.stringify(
101
- state.validationError ?? {},
102
- null,
103
- 2,
104
- )}
105
- isReadOnly={true}
106
- language={CODE_EDITOR_LANGUAGE.JSON}
107
- />
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>
164
+ </div>
165
+ </div>
108
166
  </PanelContent>
109
167
  </ModalBody>
110
168
  <ModalFooter>
@@ -153,6 +211,20 @@ export const IngestDefinitionEditor = observer(() => {
153
211
  }
154
212
  };
155
213
 
214
+ const renderDeploymentResponse = (): React.ReactNode => {
215
+ const response = ingestDefinitionEditorState.deploymentResponse;
216
+ if (response instanceof IngestDefinitionValidationResponse) {
217
+ return (
218
+ <IngestValidationError
219
+ state={ingestDefinitionEditorState}
220
+ validateResponse={response}
221
+ />
222
+ );
223
+ }
224
+
225
+ return null;
226
+ };
227
+
156
228
  const isValid = ingestDefinitionEditorState.validForDeployment;
157
229
  useEffect(() => {
158
230
  ingestDefinitionEditorState.generateElementGrammar();
@@ -202,12 +274,7 @@ export const IngestDefinitionEditor = observer(() => {
202
274
  language={CODE_EDITOR_LANGUAGE.PURE}
203
275
  />
204
276
  </PanelContent>
205
- {ingestDefinitionEditorState.deploymentState.isInProgress && (
206
- <IngestDepoymentModal state={ingestDefinitionEditorState} />
207
- )}
208
- {ingestDefinitionEditorState.validationError && (
209
- <IngestValidationError state={ingestDefinitionEditorState} />
210
- )}
277
+ {renderDeploymentResponse()}
211
278
  </PanelContent>
212
279
  </div>
213
280
  );
@@ -27,7 +27,6 @@ import {
27
27
  NewServiceDriver,
28
28
  CONNECTION_TYPE,
29
29
  type RuntimeOption,
30
- NewLakehouseDataProductDriver,
31
30
  } from '../../../stores/editor/NewElementState.js';
32
31
  import { Dialog, compareLabelFn, CustomSelectorInput } from '@finos/legend-art';
33
32
  import type { EditorStore } from '../../../stores/editor/EditorStore.js';
@@ -441,27 +440,11 @@ const NewServiceDriverEditor = observer(() => {
441
440
  });
442
441
 
443
442
  const NewLakehouseDataProductEditor = observer(() => {
444
- const editorStore = useEditorStore();
445
- const newProductDriver = editorStore.newElementState.getNewElementDriver(
446
- NewLakehouseDataProductDriver,
447
- );
448
- const handleTitleChangee: React.ChangeEventHandler<HTMLInputElement> = (
449
- event,
450
- ) => newProductDriver.setTitle(event.target.value);
451
- return (
452
- <>
453
- <div className="panel__content__form__section__header__label">Title</div>
454
- <div className="explorer__new-element-modal__driver">
455
- <input
456
- className="input--dark explorer__new-element-modal__name-input"
457
- spellCheck={false}
458
- value={newProductDriver.title}
459
- onChange={handleTitleChangee}
460
- placeholder={`Data Product Title`}
461
- />
462
- </div>
463
- </>
464
- );
443
+ // const editorStore = useEditorStore();
444
+ // const newProductDriver = editorStore.newElementState.getNewElementDriver(
445
+ // NewLakehouseDataProductDriver,
446
+ // );
447
+ return null;
465
448
  });
466
449
 
467
450
  const NewFileGenerationDriverEditor = observer(() => {
@@ -496,7 +496,7 @@ export class NewLakehouseDataProductDriver extends NewElementDriver<DataProduct>
496
496
  }
497
497
 
498
498
  override get isValid(): boolean {
499
- return Boolean(this.title);
499
+ return true;
500
500
  }
501
501
 
502
502
  setTitle(val: string) {