@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.
- package/lib/__lib__/LegendStudioDocumentation.d.ts +1 -0
- package/lib/__lib__/LegendStudioDocumentation.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioDocumentation.js +1 -0
- package/lib/__lib__/LegendStudioDocumentation.js.map +1 -1
- package/lib/application/LegendStudioApplicationConfig.d.ts +6 -0
- package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
- package/lib/application/LegendStudioApplicationConfig.js +7 -0
- package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js +67 -15
- package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js.map +1 -1
- package/lib/components/editor/editor-group/function-activator/FunctionEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/function-activator/FunctionEditor.js +43 -5
- package/lib/components/editor/editor-group/function-activator/FunctionEditor.js.map +1 -1
- package/lib/components/editor/side-bar/CreateNewElementModal.d.ts.map +1 -1
- package/lib/components/editor/side-bar/CreateNewElementModal.js +11 -1
- package/lib/components/editor/side-bar/CreateNewElementModal.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/EditorTabManagerState.js +1 -1
- package/lib/stores/editor/EditorTabManagerState.js.map +1 -1
- package/lib/stores/editor/NewElementState.d.ts +8 -1
- package/lib/stores/editor/NewElementState.d.ts.map +1 -1
- package/lib/stores/editor/NewElementState.js +28 -1
- package/lib/stores/editor/NewElementState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.d.ts +5 -0
- package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.js +13 -0
- package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/FunctionEditorState.d.ts +2 -1
- package/lib/stores/editor/editor-state/element-editor-state/FunctionEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/FunctionEditorState.js +16 -2
- package/lib/stores/editor/editor-state/element-editor-state/FunctionEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +33 -11
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js +139 -36
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.d.ts +4 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.js +7 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.d.ts +4 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.js +7 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.js.map +1 -1
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts +1 -0
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js +3 -0
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js.map +1 -1
- package/lib/stores/ingestion/AdhocDataProductDeployResponse.d.ts +21 -0
- package/lib/stores/ingestion/AdhocDataProductDeployResponse.d.ts.map +1 -0
- package/lib/stores/ingestion/AdhocDataProductDeployResponse.js +24 -0
- package/lib/stores/ingestion/AdhocDataProductDeployResponse.js.map +1 -0
- package/lib/stores/ingestion/IngestDeploymentServerClient.d.ts +4 -0
- package/lib/stores/ingestion/IngestDeploymentServerClient.d.ts.map +1 -1
- package/lib/stores/ingestion/IngestDeploymentServerClient.js +5 -0
- package/lib/stores/ingestion/IngestDeploymentServerClient.js.map +1 -1
- package/lib/stores/ingestion/IngestionManager.d.ts +2 -0
- package/lib/stores/ingestion/IngestionManager.d.ts.map +1 -1
- package/lib/stores/ingestion/IngestionManager.js +8 -0
- package/lib/stores/ingestion/IngestionManager.js.map +1 -1
- package/package.json +6 -6
- package/src/__lib__/LegendStudioDocumentation.ts +1 -0
- package/src/application/LegendStudioApplicationConfig.ts +8 -1
- package/src/components/editor/editor-group/dataProduct/DataPoductEditor.tsx +178 -8
- package/src/components/editor/editor-group/function-activator/FunctionEditor.tsx +108 -6
- package/src/components/editor/side-bar/CreateNewElementModal.tsx +29 -0
- package/src/stores/editor/EditorTabManagerState.ts +1 -1
- package/src/stores/editor/NewElementState.ts +34 -1
- package/src/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.ts +22 -0
- package/src/stores/editor/editor-state/element-editor-state/FunctionEditorState.ts +25 -2
- package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +212 -48
- package/src/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.ts +9 -0
- package/src/stores/editor/editor-state/element-editor-state/mapping/relational/RelationalInstanceSetImplementationState.ts +10 -0
- package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +6 -0
- package/src/stores/ingestion/AdhocDataProductDeployResponse.ts +29 -0
- package/src/stores/ingestion/IngestDeploymentServerClient.ts +18 -0
- package/src/stores/ingestion/IngestionManager.ts +25 -0
- 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.
|
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.
|
73
|
-
.map((e) => e.
|
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.
|
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
|
-
|
519
|
-
|
520
|
-
|
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-
|
1038
|
-
|
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 =
|
1035
|
+
element = this.getNewElementDriver(
|
1036
|
+
NewLakehouseDataProductDriver,
|
1037
|
+
).createElement(name);
|
1005
1038
|
break;
|
1006
1039
|
default: {
|
1007
1040
|
const extraNewElementFromStateCreators = this.editorStore.pluginManager
|
package/src/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.ts
CHANGED
@@ -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 {
|