@finos/legend-application-studio 28.18.130 → 28.18.132

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 (80) hide show
  1. package/lib/__lib__/LegendStudioDocumentation.d.ts +1 -0
  2. package/lib/__lib__/LegendStudioDocumentation.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioDocumentation.js +1 -0
  4. package/lib/__lib__/LegendStudioDocumentation.js.map +1 -1
  5. package/lib/application/LegendStudioApplicationConfig.d.ts +6 -0
  6. package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
  7. package/lib/application/LegendStudioApplicationConfig.js +7 -0
  8. package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
  9. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.d.ts.map +1 -1
  10. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js +67 -15
  11. package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js.map +1 -1
  12. package/lib/components/editor/editor-group/function-activator/FunctionEditor.d.ts.map +1 -1
  13. package/lib/components/editor/editor-group/function-activator/FunctionEditor.js +43 -5
  14. package/lib/components/editor/editor-group/function-activator/FunctionEditor.js.map +1 -1
  15. package/lib/components/editor/side-bar/CreateNewElementModal.d.ts.map +1 -1
  16. package/lib/components/editor/side-bar/CreateNewElementModal.js +11 -1
  17. package/lib/components/editor/side-bar/CreateNewElementModal.js.map +1 -1
  18. package/lib/index.css +2 -2
  19. package/lib/index.css.map +1 -1
  20. package/lib/package.json +1 -1
  21. package/lib/stores/editor/EditorTabManagerState.js +1 -1
  22. package/lib/stores/editor/EditorTabManagerState.js.map +1 -1
  23. package/lib/stores/editor/NewElementState.d.ts +8 -1
  24. package/lib/stores/editor/NewElementState.d.ts.map +1 -1
  25. package/lib/stores/editor/NewElementState.js +28 -1
  26. package/lib/stores/editor/NewElementState.js.map +1 -1
  27. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.d.ts +5 -0
  28. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.d.ts.map +1 -1
  29. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.js +13 -0
  30. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.js.map +1 -1
  31. package/lib/stores/editor/editor-state/element-editor-state/FunctionEditorState.d.ts +2 -1
  32. package/lib/stores/editor/editor-state/element-editor-state/FunctionEditorState.d.ts.map +1 -1
  33. package/lib/stores/editor/editor-state/element-editor-state/FunctionEditorState.js +16 -2
  34. package/lib/stores/editor/editor-state/element-editor-state/FunctionEditorState.js.map +1 -1
  35. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +33 -11
  36. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts.map +1 -1
  37. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js +139 -36
  38. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
  39. package/lib/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.d.ts +4 -1
  40. package/lib/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.d.ts.map +1 -1
  41. package/lib/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.js +7 -0
  42. package/lib/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.js.map +1 -1
  43. package/lib/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.d.ts +4 -1
  44. package/lib/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.d.ts.map +1 -1
  45. package/lib/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.js +7 -0
  46. package/lib/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.js.map +1 -1
  47. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts +1 -0
  48. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
  49. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js +3 -0
  50. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js.map +1 -1
  51. package/lib/stores/ingestion/AdhocDataProductDeployResponse.d.ts +21 -0
  52. package/lib/stores/ingestion/AdhocDataProductDeployResponse.d.ts.map +1 -0
  53. package/lib/stores/ingestion/AdhocDataProductDeployResponse.js +24 -0
  54. package/lib/stores/ingestion/AdhocDataProductDeployResponse.js.map +1 -0
  55. package/lib/stores/ingestion/IngestDeploymentServerClient.d.ts +4 -0
  56. package/lib/stores/ingestion/IngestDeploymentServerClient.d.ts.map +1 -1
  57. package/lib/stores/ingestion/IngestDeploymentServerClient.js +5 -0
  58. package/lib/stores/ingestion/IngestDeploymentServerClient.js.map +1 -1
  59. package/lib/stores/ingestion/IngestionManager.d.ts +2 -0
  60. package/lib/stores/ingestion/IngestionManager.d.ts.map +1 -1
  61. package/lib/stores/ingestion/IngestionManager.js +8 -0
  62. package/lib/stores/ingestion/IngestionManager.js.map +1 -1
  63. package/package.json +6 -6
  64. package/src/__lib__/LegendStudioDocumentation.ts +1 -0
  65. package/src/application/LegendStudioApplicationConfig.ts +8 -1
  66. package/src/components/editor/editor-group/dataProduct/DataPoductEditor.tsx +178 -8
  67. package/src/components/editor/editor-group/function-activator/FunctionEditor.tsx +108 -6
  68. package/src/components/editor/side-bar/CreateNewElementModal.tsx +29 -0
  69. package/src/stores/editor/EditorTabManagerState.ts +1 -1
  70. package/src/stores/editor/NewElementState.ts +34 -1
  71. package/src/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.ts +22 -0
  72. package/src/stores/editor/editor-state/element-editor-state/FunctionEditorState.ts +25 -2
  73. package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +212 -48
  74. package/src/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.ts +9 -0
  75. package/src/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.ts +10 -0
  76. package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +6 -0
  77. package/src/stores/ingestion/AdhocDataProductDeployResponse.ts +29 -0
  78. package/src/stores/ingestion/IngestDeploymentServerClient.ts +18 -0
  79. package/src/stores/ingestion/IngestionManager.ts +25 -0
  80. package/tsconfig.json +1 -0
@@ -18,6 +18,7 @@ import { observer } from 'mobx-react-lite';
18
18
  import { useEditorStore } from '../../EditorStoreProvider.js';
19
19
  import {
20
20
  DataProductEditorState,
21
+ generateUrlToDeployOnOpen,
21
22
  LakehouseAccessPointState,
22
23
  } from '../../../../stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js';
23
24
  import {
@@ -34,11 +35,21 @@ import {
34
35
  TimesIcon,
35
36
  PlusIcon,
36
37
  PanelHeaderActionItem,
38
+ RocketIcon,
39
+ Modal,
40
+ ModalHeader,
41
+ ModalTitle,
42
+ ModalBody,
43
+ ModalFooter,
44
+ ModalFooterButton,
37
45
  } from '@finos/legend-art';
38
46
  import { useRef, useState, useEffect } from 'react';
39
47
  import { filterByType } from '@finos/legend-shared';
40
48
  import { InlineLambdaEditor } from '@finos/legend-query-builder';
41
49
  import { flowResult } from 'mobx';
50
+ import { useAuth } from 'react-oidc-context';
51
+ import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
52
+ import { CodeEditor } from '@finos/legend-lego/code-editor';
42
53
 
43
54
  const NewAccessPointAccessPOint = observer(
44
55
  (props: { dataProductEditorState: DataProductEditorState }) => {
@@ -48,12 +59,18 @@ const NewAccessPointAccessPOint = observer(
48
59
  const handleIdChange: React.ChangeEventHandler<HTMLInputElement> = (
49
60
  event,
50
61
  ) => setId(event.target.value);
62
+ const [description, setDescription] = useState<string | undefined>(
63
+ undefined,
64
+ );
65
+ const handleDescriptionChange: React.ChangeEventHandler<
66
+ HTMLInputElement
67
+ > = (event) => setDescription(event.target.value);
51
68
  const handleClose = () => {
52
69
  dataProductEditorState.setAccessPointModal(false);
53
70
  };
54
71
  const handleSubmit = () => {
55
72
  if (id) {
56
- dataProductEditorState.addAccessPoint(id);
73
+ dataProductEditorState.addAccessPoint(id, description, 'default');
57
74
  handleClose();
58
75
  }
59
76
  };
@@ -63,14 +80,12 @@ const NewAccessPointAccessPOint = observer(
63
80
  const disableCreateButton =
64
81
  id === '' ||
65
82
  id === undefined ||
66
- dataProductEditorState.accessPointStates
67
- .map((e) => e.accessPoint.id)
68
- .includes(id);
83
+ dataProductEditorState.accessPoints.map((e) => e.id).includes(id);
69
84
  const errors =
70
85
  id === ''
71
86
  ? `ID is empty`
72
- : dataProductEditorState.accessPointStates
73
- .map((e) => e.accessPoint.id)
87
+ : dataProductEditorState.accessPoints
88
+ .map((e) => e.id)
74
89
  .includes(id ?? '')
75
90
  ? `ID already exists`
76
91
  : undefined;
@@ -101,6 +116,9 @@ const NewAccessPointAccessPOint = observer(
101
116
  >
102
117
  <div className="modal__title">New Access Point</div>
103
118
  <div>
119
+ <div className="panel__content__form__section__header__label">
120
+ ID
121
+ </div>
104
122
  <InputWithInlineValidation
105
123
  className={clsx('input new-access-point-modal__id-input', {
106
124
  'input--dark': true,
@@ -113,6 +131,21 @@ const NewAccessPointAccessPOint = observer(
113
131
  error={errors}
114
132
  />
115
133
  </div>
134
+ <div>
135
+ <div className="panel__content__form__section__header__label">
136
+ Description
137
+ </div>
138
+ <InputWithInlineValidation
139
+ className={clsx('input new-access-point-modal__id-input', {
140
+ 'input--dark': true,
141
+ })}
142
+ spellCheck={false}
143
+ value={description}
144
+ onChange={handleDescriptionChange}
145
+ placeholder="Access Point Description"
146
+ error={errors}
147
+ />
148
+ </div>
116
149
  <PanelDivider />
117
150
  <div className="search-modal__actions">
118
151
  <button
@@ -172,7 +205,7 @@ export const LakehouseDataProductAcccessPointEditor = observer(
172
205
  <InlineLambdaEditor
173
206
  className={'access-point-editor__lambda-editor'}
174
207
  disabled={
175
- lambdaEditorState.val.state
208
+ lambdaEditorState.val.state.state
176
209
  .isConvertingTransformLambdaObjects
177
210
  }
178
211
  lambdaEditorState={lambdaEditorState}
@@ -232,16 +265,119 @@ const DataProductEditorSplashScreen = observer(
232
265
  },
233
266
  );
234
267
 
268
+ const DataproductDeploymenetModal = observer(
269
+ (props: { state: DataProductEditorState }) => {
270
+ const { state } = props;
271
+ const applicationStore = state.editorStore.applicationStore;
272
+ return (
273
+ <Dialog
274
+ open={state.deploymentState.isInProgress}
275
+ classes={{ container: 'search-modal__container' }}
276
+ >
277
+ <Modal
278
+ darkMode={
279
+ !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
280
+ }
281
+ className="database-builder"
282
+ >
283
+ <ModalHeader>
284
+ <ModalTitle title="Deploy Data Product" />
285
+ </ModalHeader>
286
+ <ModalBody>
287
+ <div>{state.deploymentState.message}</div>
288
+ </ModalBody>
289
+ </Modal>
290
+ </Dialog>
291
+ );
292
+ },
293
+ );
294
+
295
+ const DataProductDeploymentResponseModal = observer(
296
+ (props: { state: DataProductEditorState }) => {
297
+ const { state } = props;
298
+ const applicationStore = state.editorStore.applicationStore;
299
+ const closeModal = (): void => state.setDeployResponse(undefined);
300
+ return (
301
+ <Dialog
302
+ open={Boolean(state.deployResponse)}
303
+ classes={{
304
+ root: 'editor-modal__root-container',
305
+ container: 'editor-modal__container',
306
+ paper: 'editor-modal__content',
307
+ }}
308
+ onClose={closeModal}
309
+ >
310
+ <Modal
311
+ darkMode={
312
+ !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
313
+ }
314
+ className="editor-modal"
315
+ >
316
+ <ModalHeader>
317
+ <ModalTitle title="Validation Error" />
318
+ </ModalHeader>
319
+ <ModalBody>
320
+ <PanelContent>
321
+ <CodeEditor
322
+ inputValue={JSON.stringify(
323
+ state.deployResponse?.content ?? {},
324
+ null,
325
+ 2,
326
+ )}
327
+ isReadOnly={true}
328
+ language={CODE_EDITOR_LANGUAGE.JSON}
329
+ />
330
+ </PanelContent>
331
+ </ModalBody>
332
+ <ModalFooter>
333
+ <ModalFooterButton
334
+ onClick={closeModal}
335
+ text="Close"
336
+ type="secondary"
337
+ />
338
+ </ModalFooter>
339
+ </Modal>
340
+ </Dialog>
341
+ );
342
+ },
343
+ );
344
+
235
345
  export const DataProductEditor = observer(() => {
236
346
  const editorStore = useEditorStore();
237
347
  const dataProductEditorState =
238
348
  editorStore.tabManagerState.getCurrentEditorState(DataProductEditorState);
239
349
  const product = dataProductEditorState.product;
240
- const accessPointStates = dataProductEditorState.accessPointStates;
350
+ const accessPointStates = dataProductEditorState.accessPointGroupStates
351
+ .map((e) => e.accessPointStates)
352
+ .flat();
241
353
  const isReadOnly = dataProductEditorState.isReadOnly;
242
354
  const openNewModal = () => {
243
355
  dataProductEditorState.setAccessPointModal(true);
244
356
  };
357
+ const auth = useAuth();
358
+ const deployDataProduct = (): void => {
359
+ // Trigger OAuth flow if not authenticated
360
+ if (!auth.isAuthenticated) {
361
+ // remove this redirect if we move to do oauth at the beginning of opening studio
362
+ auth
363
+ .signinRedirect({
364
+ state: generateUrlToDeployOnOpen(dataProductEditorState),
365
+ })
366
+ .catch(editorStore.applicationStore.alertUnhandledError);
367
+ return;
368
+ }
369
+ // Use the token for deployment
370
+ const token = auth.user?.access_token;
371
+ if (token) {
372
+ flowResult(dataProductEditorState.deploy(token)).catch(
373
+ editorStore.applicationStore.alertUnhandledError,
374
+ );
375
+ } else {
376
+ editorStore.applicationStore.notificationService.notifyError(
377
+ 'Authentication failed. No token available.',
378
+ );
379
+ }
380
+ };
245
381
 
246
382
  useEffect(() => {
247
383
  flowResult(dataProductEditorState.convertAccessPointsFuncObjects()).catch(
@@ -249,6 +385,18 @@ export const DataProductEditor = observer(() => {
249
385
  );
250
386
  }, [dataProductEditorState]);
251
387
 
388
+ useEffect(() => {
389
+ if (dataProductEditorState.deployOnOpen) {
390
+ flowResult(dataProductEditorState.deploy(auth.user?.access_token)).catch(
391
+ editorStore.applicationStore.alertUnhandledError,
392
+ );
393
+ }
394
+ }, [
395
+ auth,
396
+ editorStore.applicationStore.alertUnhandledError,
397
+ dataProductEditorState,
398
+ ]);
399
+
252
400
  return (
253
401
  <div className="data-product-editor">
254
402
  <div className="panel">
@@ -262,6 +410,20 @@ export const DataProductEditor = observer(() => {
262
410
  <div className="panel__header__title__label">data product</div>
263
411
  <div className="panel__header__title__content">{product.name}</div>
264
412
  </div>
413
+ <PanelHeaderActions>
414
+ <div className="btn__dropdown-combo btn__dropdown-combo--primary">
415
+ <button
416
+ className="btn__dropdown-combo__label"
417
+ onClick={deployDataProduct}
418
+ title={dataProductEditorState.deployValidationMessage}
419
+ tabIndex={-1}
420
+ disabled={!dataProductEditorState.deployValidationMessage}
421
+ >
422
+ <RocketIcon className="btn__dropdown-combo__label__icon" />
423
+ <div className="btn__dropdown-combo__label__title">Deploy</div>
424
+ </button>
425
+ </div>
426
+ </PanelHeaderActions>
265
427
  </div>
266
428
  <div className="panel">
267
429
  <PanelHeader>
@@ -300,6 +462,14 @@ export const DataProductEditor = observer(() => {
300
462
  dataProductEditorState={dataProductEditorState}
301
463
  />
302
464
  )}
465
+ {dataProductEditorState.deploymentState.isInProgress && (
466
+ <DataproductDeploymenetModal state={dataProductEditorState} />
467
+ )}
468
+ {dataProductEditorState.deployResponse && (
469
+ <DataProductDeploymentResponseModal
470
+ state={dataProductEditorState}
471
+ />
472
+ )}
303
473
  </div>
304
474
  </div>
305
475
  </div>
@@ -66,6 +66,8 @@ import {
66
66
  Snowflake_BrandIcon,
67
67
  InputWithInlineValidation,
68
68
  LongArrowRightIcon,
69
+ CheckSquareIcon,
70
+ SquareIcon,
69
71
  } from '@finos/legend-art';
70
72
  import { LEGEND_STUDIO_TEST_ID } from '../../../../__lib__/LegendStudioTesting.js';
71
73
  import {
@@ -105,6 +107,10 @@ import {
105
107
  RelationalDatabaseConnection,
106
108
  type FunctionActivator,
107
109
  GenericType,
110
+ requireTypeArugments,
111
+ GenericTypeExplicitReference,
112
+ CORE_PURE_PATH,
113
+ TDSExecutionResult,
108
114
  } from '@finos/legend-graph';
109
115
  import {
110
116
  type ApplicationStore,
@@ -141,9 +147,12 @@ import {
141
147
  type QueryBuilderState,
142
148
  ExecutionPlanViewer,
143
149
  FunctionQueryBuilderState,
150
+ getTDSColumnCustomizations,
144
151
  LambdaEditor,
145
152
  LambdaParameterValuesEditor,
153
+ QUERY_BUILDER_TEST_ID,
146
154
  QueryBuilderAdvancedWorkflowState,
155
+ getRowDataFromExecutionResult,
147
156
  } from '@finos/legend-query-builder';
148
157
  import type { EditorStore } from '../../../../stores/editor/EditorStore.js';
149
158
  import { graph_renameElement } from '../../../../stores/graph-modifier/GraphModifierHelper.js';
@@ -155,6 +164,10 @@ import { FunctionTestableEditor } from './testable/FunctionTestableEditor.js';
155
164
  import { DocumentationLink } from '@finos/legend-lego/application';
156
165
  import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../../__lib__/LegendStudioDocumentation.js';
157
166
  import { openDataCube } from '../../../../stores/editor/data-cube/LegendStudioDataCubeHelper.js';
167
+ import {
168
+ DataGrid,
169
+ type DataGridColumnDefinition,
170
+ } from '@finos/legend-lego/data-grid';
158
171
 
159
172
  enum FUNCTION_PARAMETER_TYPE {
160
173
  CLASS = 'CLASS',
@@ -515,10 +528,18 @@ const ReturnTypeEditor = observer(
515
528
  label: returnType.value.rawType.name,
516
529
  };
517
530
  const changeType = (val: PackageableElementOption<Type>): void => {
518
- function_setReturnGenericType(
519
- functionElement,
520
- new GenericType(val.value),
521
- );
531
+ const value = val.value;
532
+ const genericType = new GenericType(value);
533
+ if (requireTypeArugments(value)) {
534
+ genericType.typeArguments = [
535
+ GenericTypeExplicitReference.create(
536
+ new GenericType(
537
+ editorStore.graphManagerState.graph.getType(CORE_PURE_PATH.ANY),
538
+ ),
539
+ ),
540
+ ];
541
+ }
542
+ function_setReturnGenericType(functionElement, genericType);
522
543
  setIsEditingType(false);
523
544
  updateFunctionName(editorStore, applicationStore, functionElement);
524
545
  };
@@ -959,6 +980,53 @@ const FunctionDefinitionEditor = observer(
959
980
  isReadOnly={true}
960
981
  />
961
982
  );
983
+ } else if (execResult instanceof TDSExecutionResult) {
984
+ const colDefs = execResult.result.columns.map(
985
+ (colName) =>
986
+ ({
987
+ minWidth: 50,
988
+ sortable: true,
989
+ resizable: true,
990
+ field: colName,
991
+ flex: 1,
992
+ headerName: colName,
993
+ ...getTDSColumnCustomizations(execResult, colName),
994
+ }) as DataGridColumnDefinition,
995
+ );
996
+ return (
997
+ <div
998
+ data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_VALUES_TDS}
999
+ className="query-builder__result__values__table"
1000
+ >
1001
+ <div
1002
+ className={clsx('query-builder__result__tds-grid', {
1003
+ 'ag-theme-balham': true,
1004
+ 'ag-theme-balham-dark': true,
1005
+ })}
1006
+ >
1007
+ <DataGrid
1008
+ rowData={getRowDataFromExecutionResult(execResult)}
1009
+ gridOptions={{
1010
+ suppressScrollOnNewData: true,
1011
+ getRowId: (data) => `${data.data.rowNumber}`,
1012
+ rowSelection: {
1013
+ mode: 'multiRow',
1014
+ checkboxes: false,
1015
+ headerCheckbox: false,
1016
+ },
1017
+ }}
1018
+ // NOTE: when column definition changed, we need to force refresh the cell to make sure the cell renderer is updated
1019
+ // See https://stackoverflow.com/questions/56341073/how-to-refresh-an-ag-grid-when-a-change-occurs-inside-a-custom-cell-renderer-com
1020
+ onRowDataUpdated={(params) => {
1021
+ params.api.refreshCells({ force: true });
1022
+ }}
1023
+ suppressFieldDotNotation={true}
1024
+ suppressContextMenu={false}
1025
+ columnDefs={colDefs}
1026
+ />
1027
+ </div>
1028
+ </div>
1029
+ );
962
1030
  } else if (execResult !== undefined) {
963
1031
  const json =
964
1032
  returnUndefOnError(() =>
@@ -1034,8 +1102,42 @@ const FunctionDefinitionEditor = observer(
1034
1102
  </div>
1035
1103
  <div className="function-editor__definition__item">
1036
1104
  <div className="function-editor__definition__item__header">
1037
- <div className="function-editor__definition__item__header__title">
1038
- LAMBDA
1105
+ <div className="function-editor__definition__item__header-wrapper">
1106
+ <div className="function-editor__definition__item__header__title">
1107
+ LAMBDA
1108
+ </div>
1109
+ <div className="function-editor__definition__typeAhead">
1110
+ <div className="function-editor__definition__typeAhead__label">
1111
+ (BETA) TypeAhead
1112
+ <DocumentationLink
1113
+ title="Enable TypeAhead for when typing your function. Caution when using against bigger projects as requires compilation to work"
1114
+ documentationKey={
1115
+ LEGEND_STUDIO_DOCUMENTATION_KEY.QUESTION_HOW_TO_ENABLE_TYPEAHEAD
1116
+ }
1117
+ />
1118
+ </div>
1119
+ <button
1120
+ className={clsx(
1121
+ 'function-editor__definition__typeAhead__toggler__btn',
1122
+ {
1123
+ 'function-editor__definition__typeAhead__toggler__btn--toggled':
1124
+ lambdaEditorState.typeAheadEnabled,
1125
+ },
1126
+ )}
1127
+ onClick={() =>
1128
+ lambdaEditorState.setTypeAhead(
1129
+ !lambdaEditorState.typeAheadEnabled,
1130
+ )
1131
+ }
1132
+ tabIndex={-1}
1133
+ >
1134
+ {lambdaEditorState.typeAheadEnabled ? (
1135
+ <CheckSquareIcon />
1136
+ ) : (
1137
+ <SquareIcon />
1138
+ )}
1139
+ </button>
1140
+ </div>
1039
1141
  </div>
1040
1142
  <div>
1041
1143
  <ReturnTypeEditor
@@ -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';
@@ -439,6 +440,30 @@ const NewServiceDriverEditor = observer(() => {
439
440
  );
440
441
  });
441
442
 
443
+ 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
+ );
465
+ });
466
+
442
467
  const NewFileGenerationDriverEditor = observer(() => {
443
468
  const editorStore = useEditorStore();
444
469
  const applicationStore = editorStore.applicationStore;
@@ -485,6 +510,10 @@ const renderNewElementDriver = (
485
510
  return <NewDataElementDriverEditor />;
486
511
  case PACKAGEABLE_ELEMENT_TYPE.SERVICE:
487
512
  return <NewServiceDriverEditor />;
513
+ case PACKAGEABLE_ELEMENT_TYPE.SERVICE:
514
+ return <NewServiceDriverEditor />;
515
+ case PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT:
516
+ return <NewLakehouseDataProductEditor />;
488
517
  default: {
489
518
  const extraNewElementDriverEditorCreators = editorStore.pluginManager
490
519
  .getApplicationPlugins()
@@ -182,7 +182,7 @@ export class EditorTabManagerState extends TabManagerState {
182
182
  } else if (element instanceof Service) {
183
183
  return new ServiceEditorState(this.editorStore, element);
184
184
  } else if (element instanceof DataProduct) {
185
- return new DataProductEditorState(this.editorStore, element);
185
+ return new DataProductEditorState(this.editorStore, element, config);
186
186
  } else if (element instanceof GenerationSpecification) {
187
187
  return new GenerationSpecificationEditorState(this.editorStore, element);
188
188
  } else if (element instanceof FileGenerationSpecification) {
@@ -109,6 +109,7 @@ 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
113
 
113
114
  export const CUSTOM_LABEL = '(custom)';
114
115
 
@@ -481,6 +482,33 @@ export class NewPackageableConnectionDriver extends NewElementDriver<Packageable
481
482
  }
482
483
  }
483
484
 
485
+ export class NewLakehouseDataProductDriver extends NewElementDriver<DataProduct> {
486
+ title: string;
487
+
488
+ constructor(editorStore: EditorStore) {
489
+ super(editorStore);
490
+ this.title = '';
491
+ makeObservable(this, {
492
+ title: observable,
493
+ setTitle: action,
494
+ isValid: computed,
495
+ });
496
+ }
497
+
498
+ override get isValid(): boolean {
499
+ return Boolean(this.title);
500
+ }
501
+
502
+ setTitle(val: string) {
503
+ this.title = val;
504
+ }
505
+ override createElement(name: string): DataProduct {
506
+ const dataProduct = new DataProduct(name);
507
+ dataProduct_setTitle(dataProduct, this.title);
508
+ return dataProduct;
509
+ }
510
+ }
511
+
484
512
  export class NewServiceDriver extends NewElementDriver<Service> {
485
513
  mappingOption?: PackageableElementOption<Mapping> | undefined;
486
514
  runtimeOption: RuntimeOption;
@@ -767,6 +795,9 @@ export class NewElementState {
767
795
  case PACKAGEABLE_ELEMENT_TYPE.SERVICE:
768
796
  driver = new NewServiceDriver(this.editorStore);
769
797
  break;
798
+ case PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT:
799
+ driver = new NewLakehouseDataProductDriver(this.editorStore);
800
+ break;
770
801
  default: {
771
802
  const extraNewElementDriverCreators = this.editorStore.pluginManager
772
803
  .getApplicationPlugins()
@@ -1001,7 +1032,9 @@ export class NewElementState {
1001
1032
  element = new GenerationSpecification(name);
1002
1033
  break;
1003
1034
  case PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT:
1004
- element = new DataProduct(name);
1035
+ element = this.getNewElementDriver(
1036
+ NewLakehouseDataProductDriver,
1037
+ ).createElement(name);
1005
1038
  break;
1006
1039
  default: {
1007
1040
  const extraNewElementFromStateCreators = this.editorStore.pluginManager
@@ -48,6 +48,18 @@ export class IngestElementEditorInitialConfiguration extends ElementEditorInitia
48
48
  );
49
49
  }
50
50
 
51
+ export class DataProductElementEditorInitialConfiguration extends ElementEditorInitialConfiguration {
52
+ deployOnOpen?: boolean;
53
+ type = PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT;
54
+
55
+ static readonly serialization = new SerializationFactory(
56
+ createModelSchema(DataProductElementEditorInitialConfiguration, {
57
+ _type: usingConstantValueSchema(PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT),
58
+ deployOnOpen: optional(primitive()),
59
+ }),
60
+ );
61
+ }
62
+
51
63
  const serializeElementEditorInitialConfiguration = (
52
64
  protocol: ElementEditorInitialConfiguration,
53
65
  ): PlainObject<ElementEditorInitialConfiguration> => {
@@ -56,6 +68,11 @@ const serializeElementEditorInitialConfiguration = (
56
68
  IngestElementEditorInitialConfiguration.serialization.schema,
57
69
  protocol,
58
70
  );
71
+ } else if (protocol instanceof DataProductElementEditorInitialConfiguration) {
72
+ return serialize(
73
+ DataProductElementEditorInitialConfiguration.serialization.schema,
74
+ protocol,
75
+ );
59
76
  }
60
77
  throw new UnsupportedOperationError(
61
78
  `Can't serialize element config`,
@@ -72,6 +89,11 @@ const deseralizeElementEditorInitialConfiguration = (
72
89
  IngestElementEditorInitialConfiguration.serialization.schema,
73
90
  json,
74
91
  );
92
+ case PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT:
93
+ return deserialize(
94
+ DataProductElementEditorInitialConfiguration.serialization.schema,
95
+ json,
96
+ );
75
97
  default: {
76
98
  throw new UnsupportedOperationError(
77
99
  `Can't deserialize element config`,
@@ -55,6 +55,7 @@ import {
55
55
  generateFunctionPrettyName,
56
56
  RawVariableExpression,
57
57
  type FunctionActivator,
58
+ CodeCompletionResult,
58
59
  } from '@finos/legend-graph';
59
60
  import {
60
61
  ExecutionPlanState,
@@ -88,13 +89,15 @@ export class FunctionDefinitionEditorState extends LambdaEditorState {
88
89
  functionElement: ConcreteFunctionDefinition,
89
90
  editorStore: EditorStore,
90
91
  ) {
91
- super('', LAMBDA_PIPE);
92
+ super('', LAMBDA_PIPE, {
93
+ typeAheadEnabled:
94
+ editorStore.applicationStore.config.options.typeAheadEnabled,
95
+ });
92
96
 
93
97
  makeObservable(this, {
94
98
  functionElement: observable,
95
99
  isConvertingFunctionBodyToString: observable,
96
100
  });
97
-
98
101
  this.functionElement = functionElement;
99
102
  this.editorStore = editorStore;
100
103
  }
@@ -189,6 +192,26 @@ export class FunctionDefinitionEditorState extends LambdaEditorState {
189
192
  this.setLambdaString('');
190
193
  }
191
194
  }
195
+
196
+ override async getCodeComplete(input: string): Promise<CodeCompletionResult> {
197
+ try {
198
+ return (await this.editorStore.graphManagerState.graphManager.getCodeComplete(
199
+ input,
200
+ this.editorStore.graphManagerState.graph,
201
+ undefined,
202
+ {
203
+ ignoreElements: [this.functionElement.path],
204
+ },
205
+ )) as unknown as CodeCompletionResult;
206
+ } catch (error) {
207
+ assertErrorThrown(error);
208
+ this.editorStore.applicationStore.logService.error(
209
+ LogEvent.create(GRAPH_MANAGER_EVENT.PARSING_FAILURE),
210
+ error,
211
+ );
212
+ return new CodeCompletionResult();
213
+ }
214
+ }
192
215
  }
193
216
 
194
217
  export class FunctionParametersState extends LambdaParametersState {