@finos/legend-application-studio 28.21.19 → 28.21.20
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__/LegendStudioEvent.d.ts +6 -0
- package/lib/__lib__/LegendStudioEvent.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioEvent.js +7 -0
- package/lib/__lib__/LegendStudioEvent.js.map +1 -1
- package/lib/__lib__/LegendStudioTelemetryHelper.d.ts +6 -0
- package/lib/__lib__/LegendStudioTelemetryHelper.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioTelemetryHelper.js +19 -0
- package/lib/__lib__/LegendStudioTelemetryHelper.js.map +1 -1
- package/lib/components/editor/ActivityBar.d.ts +2 -4
- package/lib/components/editor/ActivityBar.d.ts.map +1 -1
- package/lib/components/editor/ActivityBar.js +3 -17
- package/lib/components/editor/ActivityBar.js.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js +56 -39
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
- package/lib/components/editor/editor-group/service-editor/ServiceEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/ServiceEditor.js +8 -1
- package/lib/components/editor/editor-group/service-editor/ServiceEditor.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/EditorGraphState.d.ts.map +1 -1
- package/lib/stores/editor/EditorGraphState.js +4 -1
- package/lib/stores/editor/EditorGraphState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +6 -2
- 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 +43 -17
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
- package/lib/stores/editor/utils/ModelClassifierUtils.d.ts +1 -0
- package/lib/stores/editor/utils/ModelClassifierUtils.d.ts.map +1 -1
- package/lib/stores/editor/utils/ModelClassifierUtils.js +1 -0
- package/lib/stores/editor/utils/ModelClassifierUtils.js.map +1 -1
- package/package.json +11 -11
- package/src/__lib__/LegendStudioEvent.ts +8 -0
- package/src/__lib__/LegendStudioTelemetryHelper.ts +61 -0
- package/src/components/editor/ActivityBar.tsx +3 -22
- package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +96 -42
- package/src/components/editor/editor-group/service-editor/ServiceEditor.tsx +17 -1
- package/src/stores/editor/EditorGraphState.ts +3 -0
- package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +98 -67
- package/src/stores/editor/utils/ModelClassifierUtils.ts +1 -0
|
@@ -19,10 +19,10 @@ import { useEditorStore } from '../../EditorStoreProvider.js';
|
|
|
19
19
|
import {
|
|
20
20
|
type AccessPointGroupState,
|
|
21
21
|
type AccessPointState,
|
|
22
|
+
type LakehouseAccessPointState,
|
|
22
23
|
DATA_PRODUCT_TAB,
|
|
23
24
|
DATA_PRODUCT_TYPE,
|
|
24
25
|
DataProductEditorState,
|
|
25
|
-
LakehouseAccessPointState,
|
|
26
26
|
ModelAccessPointGroupState,
|
|
27
27
|
} from '../../../../stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js';
|
|
28
28
|
import {
|
|
@@ -87,12 +87,12 @@ import {
|
|
|
87
87
|
useCallback,
|
|
88
88
|
useEffect,
|
|
89
89
|
useLayoutEffect,
|
|
90
|
+
useMemo,
|
|
90
91
|
useRef,
|
|
91
92
|
useState,
|
|
92
93
|
} from 'react';
|
|
93
94
|
import {
|
|
94
95
|
assertErrorThrown,
|
|
95
|
-
filterByType,
|
|
96
96
|
guaranteeNonNullable,
|
|
97
97
|
guaranteeType,
|
|
98
98
|
isNonNullable,
|
|
@@ -208,6 +208,7 @@ import type {
|
|
|
208
208
|
DataProductDocResponse,
|
|
209
209
|
DSL_DataProduct_LegendStudioApplicationPlugin_Extension,
|
|
210
210
|
} from '../../../../stores/extensions/DSL_DataProduct_LegendStudioApplicationPlugin_Extension.js';
|
|
211
|
+
import { LegendStudioTelemetryHelper } from '../../../../__lib__/LegendStudioTelemetryHelper.js';
|
|
211
212
|
|
|
212
213
|
export enum AP_GROUP_MODAL_ERRORS {
|
|
213
214
|
GROUP_NAME_EMPTY = 'Group Name is empty',
|
|
@@ -331,6 +332,17 @@ const AccessPointTitle = observer(
|
|
|
331
332
|
},
|
|
332
333
|
);
|
|
333
334
|
|
|
335
|
+
const AP_RENDER_CHUNK_SIZE = 50;
|
|
336
|
+
const AP_SENTINEL_ROOT_MARGIN = '0px 0px 400px 0px';
|
|
337
|
+
const DEFAULT_CLASSIFICATION_LABEL = 'Classification';
|
|
338
|
+
|
|
339
|
+
const toClassificationOption = (
|
|
340
|
+
classification: string,
|
|
341
|
+
): { label: string; value: string } => ({
|
|
342
|
+
label: classification,
|
|
343
|
+
value: classification,
|
|
344
|
+
});
|
|
345
|
+
|
|
334
346
|
const AccessPointClassification = observer(
|
|
335
347
|
(props: {
|
|
336
348
|
accessPoint: LakehouseAccessPoint;
|
|
@@ -338,52 +350,35 @@ const AccessPointClassification = observer(
|
|
|
338
350
|
}) => {
|
|
339
351
|
const { accessPoint, groupState } = props;
|
|
340
352
|
const applicationStore = useEditorStore().applicationStore;
|
|
341
|
-
const CHOOSE_CLASSIFICATION = 'Classification';
|
|
342
353
|
const updateAccessPointClassificationTextbox: React.ChangeEventHandler<HTMLTextAreaElement> =
|
|
343
354
|
action((event) => {
|
|
344
355
|
accessPoint.classification = event.target.value;
|
|
345
356
|
});
|
|
346
357
|
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
return (
|
|
355
|
-
applicationStore.config.options.dataProductConfig?.classifications ??
|
|
356
|
-
[]
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
const classificationOptions = [CHOOSE_CLASSIFICATION]
|
|
362
|
-
.concat(conditionalClassifications())
|
|
363
|
-
.map((classfication) => ({
|
|
364
|
-
label: classfication,
|
|
365
|
-
value: classfication,
|
|
366
|
-
}));
|
|
358
|
+
const classificationOptions = useMemo(
|
|
359
|
+
() =>
|
|
360
|
+
[DEFAULT_CLASSIFICATION_LABEL]
|
|
361
|
+
.concat(groupState.classifications)
|
|
362
|
+
.map(toClassificationOption),
|
|
363
|
+
[groupState.classifications],
|
|
364
|
+
);
|
|
367
365
|
|
|
368
366
|
const updateAccessPointClassificationFromDropdown = action(
|
|
369
367
|
(val: { label: string; value: string } | null): void => {
|
|
370
368
|
accessPoint_setClassification(
|
|
371
369
|
accessPoint,
|
|
372
|
-
val?.value ===
|
|
370
|
+
val?.value === DEFAULT_CLASSIFICATION_LABEL ? undefined : val?.value,
|
|
373
371
|
);
|
|
374
372
|
},
|
|
375
373
|
);
|
|
376
374
|
|
|
377
|
-
const currentClassification =
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
label: CHOOSE_CLASSIFICATION,
|
|
385
|
-
value: CHOOSE_CLASSIFICATION,
|
|
386
|
-
};
|
|
375
|
+
const currentClassification = useMemo(
|
|
376
|
+
() =>
|
|
377
|
+
toClassificationOption(
|
|
378
|
+
accessPoint.classification ?? DEFAULT_CLASSIFICATION_LABEL,
|
|
379
|
+
),
|
|
380
|
+
[accessPoint.classification],
|
|
381
|
+
);
|
|
387
382
|
|
|
388
383
|
const classificationDocumentationLink = (): void => {
|
|
389
384
|
const docLink =
|
|
@@ -399,7 +394,7 @@ const AccessPointClassification = observer(
|
|
|
399
394
|
style={{
|
|
400
395
|
borderWidth: 'thin',
|
|
401
396
|
borderColor:
|
|
402
|
-
currentClassification.label ===
|
|
397
|
+
currentClassification.label === DEFAULT_CLASSIFICATION_LABEL
|
|
403
398
|
? 'var(--color-red-300)'
|
|
404
399
|
: 'transparent',
|
|
405
400
|
}}
|
|
@@ -721,9 +716,7 @@ export const LakehouseDataProductAccessPointEditor = observer(
|
|
|
721
716
|
const accessPoint = accessPointState.accessPoint;
|
|
722
717
|
const groupState = accessPointState.state;
|
|
723
718
|
const lambdaEditorState = accessPointState.lambdaState;
|
|
724
|
-
const propertyHasParserError = groupState.
|
|
725
|
-
.filter(filterByType(LakehouseAccessPointState))
|
|
726
|
-
.find((pm) => pm.lambdaState.parserError);
|
|
719
|
+
const propertyHasParserError = groupState.hasParserError;
|
|
727
720
|
const [editingDescription, setEditingDescription] = useState(false);
|
|
728
721
|
const [isHoveringDesc, setIsHoveringDesc] = useState(false);
|
|
729
722
|
const [editingTitle, setEditingTitle] = useState(false);
|
|
@@ -736,6 +729,17 @@ export const LakehouseDataProductAccessPointEditor = observer(
|
|
|
736
729
|
);
|
|
737
730
|
}, [lambdaEditorState, editorStore.applicationStore]);
|
|
738
731
|
|
|
732
|
+
// Load the relation columns for access points that already have sample
|
|
733
|
+
// values so mismatches surface on load. This only runs for rendered access
|
|
734
|
+
// points, keeping the number of concurrent calls bounded to the visible set.
|
|
735
|
+
useEffect(() => {
|
|
736
|
+
if (accessPointState.relationElementState !== undefined) {
|
|
737
|
+
flowResult(lambdaEditorState.updateLambdaRelationColumns()).catch(
|
|
738
|
+
editorStore.applicationStore.alertUnhandledError,
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
}, [accessPointState, lambdaEditorState, editorStore.applicationStore]);
|
|
742
|
+
|
|
739
743
|
const handleDescriptionEdit = () => setEditingDescription(true);
|
|
740
744
|
const handleDescriptionBlur = () => {
|
|
741
745
|
setEditingDescription(false);
|
|
@@ -1019,7 +1023,9 @@ export const LakehouseDataProductAccessPointEditor = observer(
|
|
|
1019
1023
|
<button
|
|
1020
1024
|
className="access-point-editor__sample-values-btn"
|
|
1021
1025
|
onClick={() => {
|
|
1022
|
-
|
|
1026
|
+
flowResult(
|
|
1027
|
+
accessPointState.createAndaddRelationElement(),
|
|
1028
|
+
).catch(editorStore.applicationStore.alertUnhandledError);
|
|
1023
1029
|
}}
|
|
1024
1030
|
disabled={props.isReadOnly}
|
|
1025
1031
|
title="Add sample values"
|
|
@@ -1730,6 +1736,10 @@ const ModelAccessPointGroupEditor = observer(
|
|
|
1730
1736
|
},
|
|
1731
1737
|
);
|
|
1732
1738
|
|
|
1739
|
+
const AccessPointLoadingSentinel = (props: {
|
|
1740
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
1741
|
+
}) => <div ref={props.ref} className="access-point-editor__sentinel" />;
|
|
1742
|
+
|
|
1733
1743
|
const AccessPointGroupEditor = observer(
|
|
1734
1744
|
(props: { groupState: AccessPointGroupState; isReadOnly: boolean }) => {
|
|
1735
1745
|
const { groupState, isReadOnly } = props;
|
|
@@ -1747,6 +1757,31 @@ const AccessPointGroupEditor = observer(
|
|
|
1747
1757
|
const [aiSuggestion, setAISuggestion] = useState<
|
|
1748
1758
|
DataProductDocResponse | undefined
|
|
1749
1759
|
>(undefined);
|
|
1760
|
+
|
|
1761
|
+
const lakehouseAccessPointStates =
|
|
1762
|
+
groupState.accessPointStates as LakehouseAccessPointState[];
|
|
1763
|
+
const accessPointCount = lakehouseAccessPointStates.length;
|
|
1764
|
+
const [renderedCount, setRenderedCount] = useState(AP_RENDER_CHUNK_SIZE);
|
|
1765
|
+
const accessPointsSentinelRef = useRef<HTMLDivElement>(null);
|
|
1766
|
+
useEffect(() => {
|
|
1767
|
+
const sentinel = accessPointsSentinelRef.current;
|
|
1768
|
+
if (!sentinel) {
|
|
1769
|
+
return undefined;
|
|
1770
|
+
}
|
|
1771
|
+
const intersectionObserver = new IntersectionObserver(
|
|
1772
|
+
(entries) => {
|
|
1773
|
+
if (entries[0]?.isIntersecting) {
|
|
1774
|
+
setRenderedCount((count) =>
|
|
1775
|
+
Math.min(count + AP_RENDER_CHUNK_SIZE, accessPointCount),
|
|
1776
|
+
);
|
|
1777
|
+
}
|
|
1778
|
+
},
|
|
1779
|
+
{ rootMargin: AP_SENTINEL_ROOT_MARGIN },
|
|
1780
|
+
);
|
|
1781
|
+
intersectionObserver.observe(sentinel);
|
|
1782
|
+
return () => intersectionObserver.disconnect();
|
|
1783
|
+
}, [accessPointCount, renderedCount]);
|
|
1784
|
+
|
|
1750
1785
|
const handleDescriptionEdit = () => setEditingDescription(true);
|
|
1751
1786
|
const handleDescriptionBlur = () => {
|
|
1752
1787
|
setEditingDescription(false);
|
|
@@ -1818,6 +1853,10 @@ const AccessPointGroupEditor = observer(
|
|
|
1818
1853
|
if (!aiDocSuggester || !legendAIUrl) {
|
|
1819
1854
|
return;
|
|
1820
1855
|
}
|
|
1856
|
+
LegendStudioTelemetryHelper.logEvent_DataProductLegendAISuggestLaunched(
|
|
1857
|
+
editorStore.applicationStore.telemetryService,
|
|
1858
|
+
productEditorState.product.path,
|
|
1859
|
+
);
|
|
1821
1860
|
setIsSuggestingWithAI(true);
|
|
1822
1861
|
setAISuggestion(undefined);
|
|
1823
1862
|
try {
|
|
@@ -1843,6 +1882,10 @@ const AccessPointGroupEditor = observer(
|
|
|
1843
1882
|
if (!aiSuggestion) {
|
|
1844
1883
|
return;
|
|
1845
1884
|
}
|
|
1885
|
+
LegendStudioTelemetryHelper.logEvent_DataProductLegendAISuggestApplied(
|
|
1886
|
+
editorStore.applicationStore.telemetryService,
|
|
1887
|
+
productEditorState.product.path,
|
|
1888
|
+
);
|
|
1846
1889
|
// Find matching group in the response
|
|
1847
1890
|
const gIdx =
|
|
1848
1891
|
productEditorState.accessPointGroupStates.indexOf(groupState);
|
|
@@ -1880,6 +1923,13 @@ const AccessPointGroupEditor = observer(
|
|
|
1880
1923
|
}
|
|
1881
1924
|
setAISuggestion(undefined);
|
|
1882
1925
|
};
|
|
1926
|
+
const discardAISuggestion = (): void => {
|
|
1927
|
+
LegendStudioTelemetryHelper.logEvent_DataProductLegendAISuggestDiscarded(
|
|
1928
|
+
editorStore.applicationStore.telemetryService,
|
|
1929
|
+
productEditorState.product.path,
|
|
1930
|
+
);
|
|
1931
|
+
setAISuggestion(undefined);
|
|
1932
|
+
};
|
|
1883
1933
|
|
|
1884
1934
|
// Computed AI suggestion for current group
|
|
1885
1935
|
const groupIndex =
|
|
@@ -1922,6 +1972,7 @@ const AccessPointGroupEditor = observer(
|
|
|
1922
1972
|
undefined,
|
|
1923
1973
|
productEditorState.selectedGroupState ?? groupState,
|
|
1924
1974
|
);
|
|
1975
|
+
setRenderedCount(groupState.accessPointStates.length);
|
|
1925
1976
|
};
|
|
1926
1977
|
|
|
1927
1978
|
return (
|
|
@@ -1991,7 +2042,7 @@ const AccessPointGroupEditor = observer(
|
|
|
1991
2042
|
</button>
|
|
1992
2043
|
<button
|
|
1993
2044
|
className="btn data-product-editor__ai-suggestion__dismiss-btn"
|
|
1994
|
-
onClick={
|
|
2045
|
+
onClick={discardAISuggestion}
|
|
1995
2046
|
>
|
|
1996
2047
|
Dismiss
|
|
1997
2048
|
</button>
|
|
@@ -2150,8 +2201,8 @@ const AccessPointGroupEditor = observer(
|
|
|
2150
2201
|
<div
|
|
2151
2202
|
style={{ gap: '1rem', display: 'flex', flexDirection: 'column' }}
|
|
2152
2203
|
>
|
|
2153
|
-
{
|
|
2154
|
-
.
|
|
2204
|
+
{lakehouseAccessPointStates
|
|
2205
|
+
.slice(0, renderedCount)
|
|
2155
2206
|
.map((apState, idx) => (
|
|
2156
2207
|
<LakehouseDataProductAccessPointEditor
|
|
2157
2208
|
key={apState.uuid}
|
|
@@ -2160,6 +2211,9 @@ const AccessPointGroupEditor = observer(
|
|
|
2160
2211
|
aiSuggestionMeta={aiAccessPointMetas?.[idx]}
|
|
2161
2212
|
/>
|
|
2162
2213
|
))}
|
|
2214
|
+
{accessPointCount > renderedCount && (
|
|
2215
|
+
<AccessPointLoadingSentinel ref={accessPointsSentinelRef} />
|
|
2216
|
+
)}
|
|
2163
2217
|
</div>
|
|
2164
2218
|
</>
|
|
2165
2219
|
)}
|
|
@@ -74,6 +74,7 @@ import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../../__lib__/LegendStudi
|
|
|
74
74
|
import { DocumentationLink } from '@finos/legend-lego/application';
|
|
75
75
|
import { ServicePostValidationsEditor } from './ServicePostValidationEditor.js';
|
|
76
76
|
import type { DSL_Service_LegendStudioApplicationPlugin_Extension } from '../../../../stores/extensions/DSL_Service_LegendStudioApplicationPlugin_Extension.js';
|
|
77
|
+
import { LegendStudioTelemetryHelper } from '../../../../__lib__/LegendStudioTelemetryHelper.js';
|
|
77
78
|
|
|
78
79
|
type UserOption = { label: string; value: string };
|
|
79
80
|
|
|
@@ -264,6 +265,10 @@ const ServiceGeneralEditor = observer(() => {
|
|
|
264
265
|
if (!aiDocSuggester || !legendAIUrl) {
|
|
265
266
|
return;
|
|
266
267
|
}
|
|
268
|
+
LegendStudioTelemetryHelper.logEvent_ServiceLegendAISuggestLaunched(
|
|
269
|
+
applicationStore.telemetryService,
|
|
270
|
+
service.path,
|
|
271
|
+
);
|
|
267
272
|
setIsSuggestingWithAI(true);
|
|
268
273
|
setAIDocSuggestion(undefined);
|
|
269
274
|
try {
|
|
@@ -281,9 +286,20 @@ const ServiceGeneralEditor = observer(() => {
|
|
|
281
286
|
if (!aiDocSuggestion) {
|
|
282
287
|
return;
|
|
283
288
|
}
|
|
289
|
+
LegendStudioTelemetryHelper.logEvent_ServiceLegendAISuggestApplied(
|
|
290
|
+
applicationStore.telemetryService,
|
|
291
|
+
service.path,
|
|
292
|
+
);
|
|
284
293
|
service_setDocumentation(service, aiDocSuggestion);
|
|
285
294
|
setAIDocSuggestion(undefined);
|
|
286
295
|
};
|
|
296
|
+
const discardAIDocSuggestion = (): void => {
|
|
297
|
+
LegendStudioTelemetryHelper.logEvent_ServiceLegendAISuggestDiscarded(
|
|
298
|
+
applicationStore.telemetryService,
|
|
299
|
+
service.path,
|
|
300
|
+
);
|
|
301
|
+
setAIDocSuggestion(undefined);
|
|
302
|
+
};
|
|
287
303
|
|
|
288
304
|
const changeTitle: React.ChangeEventHandler<HTMLInputElement> = (event) => {
|
|
289
305
|
if (!isReadOnly) {
|
|
@@ -498,7 +514,7 @@ const ServiceGeneralEditor = observer(() => {
|
|
|
498
514
|
</button>
|
|
499
515
|
<button
|
|
500
516
|
className="btn service-editor__ai-suggestion__dismiss-btn"
|
|
501
|
-
onClick={
|
|
517
|
+
onClick={discardAIDocSuggestion}
|
|
502
518
|
title="Dismiss AI suggestion"
|
|
503
519
|
>
|
|
504
520
|
Dismiss
|
|
@@ -91,6 +91,7 @@ import {
|
|
|
91
91
|
SnowflakeM2MUdf,
|
|
92
92
|
GraphEntities,
|
|
93
93
|
HostedService,
|
|
94
|
+
Compute,
|
|
94
95
|
DataProduct,
|
|
95
96
|
IngestDefinition,
|
|
96
97
|
MemSQLFunction,
|
|
@@ -876,6 +877,8 @@ export class EditorGraphState {
|
|
|
876
877
|
return PACKAGEABLE_ELEMENT_TYPE.HOSTED_SERVICE;
|
|
877
878
|
} else if (element instanceof DataProduct) {
|
|
878
879
|
return PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT;
|
|
880
|
+
} else if (element instanceof Compute) {
|
|
881
|
+
return PACKAGEABLE_ELEMENT_TYPE._COMPUTE;
|
|
879
882
|
} else if (element instanceof IngestDefinition) {
|
|
880
883
|
return PACKAGEABLE_ELEMENT_TYPE.INGEST_DEFINITION;
|
|
881
884
|
} else if (element instanceof MemSQLFunction) {
|
package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts
CHANGED
|
@@ -15,56 +15,56 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
type
|
|
18
|
+
type AppDirNode,
|
|
19
|
+
type ArtifactGenerationExtensionResult,
|
|
20
|
+
type DataProductElement,
|
|
21
21
|
type IngestDefinition,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
LakehouseTargetEnv,
|
|
25
|
-
LAMBDA_PIPE,
|
|
22
|
+
type Mapping,
|
|
23
|
+
type PackageableElement,
|
|
26
24
|
type RawLambda,
|
|
27
|
-
ParserError,
|
|
28
|
-
GRAPH_MANAGER_EVENT,
|
|
29
|
-
isStubbed_RawLambda,
|
|
30
|
-
AccessPointGroup,
|
|
31
|
-
CodeCompletionResult,
|
|
32
25
|
type Stereotype,
|
|
33
|
-
getStereotype,
|
|
34
26
|
type StereotypeReference,
|
|
35
|
-
|
|
27
|
+
type V1_AccessPointGroupInfo,
|
|
28
|
+
type V1_AccessPointImplementation,
|
|
29
|
+
type V1_DataProductArtifact,
|
|
30
|
+
type V1_RawLineageModel,
|
|
31
|
+
AccessPoint,
|
|
32
|
+
AccessPointGroup,
|
|
33
|
+
AppDirOwner,
|
|
36
34
|
Association,
|
|
37
35
|
Class,
|
|
36
|
+
CodeCompletionResult,
|
|
37
|
+
DataElement,
|
|
38
|
+
DataElementReference,
|
|
39
|
+
DataProduct,
|
|
40
|
+
DataProductDiagram,
|
|
41
|
+
DataProductElementScope,
|
|
38
42
|
Enumeration,
|
|
39
|
-
Package,
|
|
40
|
-
PackageableElementExplicitReference,
|
|
41
|
-
type DataProductElement,
|
|
42
|
-
type Mapping,
|
|
43
43
|
Expertise,
|
|
44
|
+
getStereotype,
|
|
45
|
+
GRAPH_MANAGER_EVENT,
|
|
46
|
+
isStubbed_RawLambda,
|
|
47
|
+
LakehouseAccessPoint,
|
|
48
|
+
LakehouseTargetEnv,
|
|
49
|
+
LAMBDA_PIPE,
|
|
50
|
+
ModelAccessPointGroup,
|
|
51
|
+
observe_DataProductDiagram,
|
|
44
52
|
observe_DataProductElementScope,
|
|
45
|
-
DataProductElementScope,
|
|
46
|
-
type V1_RawLineageModel,
|
|
47
|
-
type ArtifactGenerationExtensionResult,
|
|
48
|
-
type V1_DataProductArtifact,
|
|
49
|
-
type V1_AccessPointGroupInfo,
|
|
50
|
-
type V1_AccessPointImplementation,
|
|
51
|
-
RelationElementsData,
|
|
52
|
-
RelationElement,
|
|
53
53
|
observe_RelationElement,
|
|
54
54
|
observe_RelationElementsData,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
Package,
|
|
56
|
+
PackageableElementExplicitReference,
|
|
57
|
+
ParserError,
|
|
58
|
+
RelationElement,
|
|
59
|
+
RelationElementsData,
|
|
60
|
+
stub_Mapping,
|
|
61
|
+
stub_RawLambda,
|
|
58
62
|
V1_GraphTransformerContextBuilder,
|
|
63
|
+
V1_LambdaReturnTypeInput,
|
|
64
|
+
V1_PureGraphManager,
|
|
59
65
|
V1_relationTypeModelSchema,
|
|
60
66
|
V1_RemoteEngine,
|
|
61
|
-
|
|
62
|
-
DataElement,
|
|
63
|
-
DataProductDiagram,
|
|
64
|
-
observe_DataProductDiagram,
|
|
65
|
-
stub_Mapping,
|
|
66
|
-
AppDirOwner,
|
|
67
|
-
type AppDirNode,
|
|
67
|
+
V1_transformRawLambda,
|
|
68
68
|
} from '@finos/legend-graph';
|
|
69
69
|
import type { EditorStore } from '../../../EditorStore.js';
|
|
70
70
|
import { ElementEditorState } from '../ElementEditorState.js';
|
|
@@ -79,35 +79,35 @@ import {
|
|
|
79
79
|
runInAction,
|
|
80
80
|
} from 'mobx';
|
|
81
81
|
import {
|
|
82
|
-
guaranteeType,
|
|
83
|
-
addUniqueEntry,
|
|
84
82
|
type GeneratorFn,
|
|
83
|
+
ActionState,
|
|
84
|
+
addUniqueEntry,
|
|
85
85
|
assertErrorThrown,
|
|
86
|
-
|
|
86
|
+
assertTrue,
|
|
87
87
|
deleteEntry,
|
|
88
88
|
filterByType,
|
|
89
|
-
ActionState,
|
|
90
89
|
guaranteeNonNullable,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
swapEntry,
|
|
90
|
+
guaranteeType,
|
|
91
|
+
LogEvent,
|
|
94
92
|
returnUndefOnError,
|
|
93
|
+
swapEntry,
|
|
94
|
+
uuid,
|
|
95
95
|
} from '@finos/legend-shared';
|
|
96
96
|
import {
|
|
97
97
|
accessPointGroup_swapAccessPoints,
|
|
98
98
|
dataProduct_addAccessPoint,
|
|
99
99
|
dataProduct_addAccessPointGroup,
|
|
100
|
-
supportInfo_addExpertise,
|
|
101
|
-
modelAccessPointGroup_addDiagram,
|
|
102
100
|
dataProduct_deleteAccessPoint,
|
|
103
101
|
dataProduct_deleteAccessPointGroup,
|
|
104
|
-
|
|
102
|
+
dataProduct_setSupportInfoIfAbsent,
|
|
105
103
|
dataProduct_swapAccessPointGroups,
|
|
104
|
+
modelAccessPointGroup_addDiagram,
|
|
106
105
|
modelAccessPointGroup_addElement,
|
|
106
|
+
modelAccessPointGroup_removeDiagram,
|
|
107
107
|
modelAccessPointGroup_removeElement,
|
|
108
108
|
modelAccessPointGroup_setElementExclude,
|
|
109
109
|
modelAccessPointGroup_setMapping,
|
|
110
|
-
|
|
110
|
+
supportInfo_addExpertise,
|
|
111
111
|
} from '../../../../graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
|
|
112
112
|
import { DataProductTestableState } from './testable/DataProductTestableState.js';
|
|
113
113
|
import { LambdaEditorState, LineageState } from '@finos/legend-query-builder';
|
|
@@ -168,6 +168,8 @@ export class AccessPointLambdaEditorState extends LambdaEditorState {
|
|
|
168
168
|
readonly val: LakehouseAccessPointState;
|
|
169
169
|
lambdaRelationColumns: string[] | undefined;
|
|
170
170
|
isUpdatingRelationColumns = false;
|
|
171
|
+
lastComputedLambdaHash: string | undefined;
|
|
172
|
+
lastComputedLambdaString: string | undefined;
|
|
171
173
|
|
|
172
174
|
constructor(val: LakehouseAccessPointState) {
|
|
173
175
|
super('', LAMBDA_PIPE, {
|
|
@@ -182,10 +184,6 @@ export class AccessPointLambdaEditorState extends LambdaEditorState {
|
|
|
182
184
|
setLambdaRelationColumns: action,
|
|
183
185
|
updateLambdaRelationColumns: flow,
|
|
184
186
|
});
|
|
185
|
-
|
|
186
|
-
flowResult(this.updateLambdaRelationColumns()).catch(
|
|
187
|
-
this.editorStore.applicationStore.alertUnhandledError,
|
|
188
|
-
);
|
|
189
187
|
}
|
|
190
188
|
|
|
191
189
|
setLambdaRelationColumns(columns: string[] | undefined): void {
|
|
@@ -202,11 +200,12 @@ export class AccessPointLambdaEditorState extends LambdaEditorState {
|
|
|
202
200
|
return;
|
|
203
201
|
}
|
|
204
202
|
|
|
205
|
-
this.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
this.val.deleteRelationElement();
|
|
203
|
+
const lambdaHash = this.val.accessPoint.func.hashCode;
|
|
204
|
+
if (lambdaHash === this.lastComputedLambdaHash) {
|
|
205
|
+
return;
|
|
209
206
|
}
|
|
207
|
+
|
|
208
|
+
this.setIsUpdatingRelationColumns(true);
|
|
210
209
|
try {
|
|
211
210
|
const model = guaranteeType(
|
|
212
211
|
this.editorStore.graphManagerState.graphManager,
|
|
@@ -244,9 +243,7 @@ export class AccessPointLambdaEditorState extends LambdaEditorState {
|
|
|
244
243
|
} catch {
|
|
245
244
|
this.setLambdaRelationColumns(undefined);
|
|
246
245
|
} finally {
|
|
247
|
-
|
|
248
|
-
this.val.addRelationElement(relationElement, false);
|
|
249
|
-
}
|
|
246
|
+
this.lastComputedLambdaHash = lambdaHash;
|
|
250
247
|
this.setIsUpdatingRelationColumns(false);
|
|
251
248
|
}
|
|
252
249
|
}
|
|
@@ -260,6 +257,9 @@ export class AccessPointLambdaEditorState extends LambdaEditorState {
|
|
|
260
257
|
}
|
|
261
258
|
|
|
262
259
|
*convertLambdaGrammarStringToObject(): GeneratorFn<void> {
|
|
260
|
+
if (this.lambdaString === this.lastComputedLambdaString) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
263
|
const emptyLambda = stub_RawLambda();
|
|
264
264
|
if (this.lambdaString) {
|
|
265
265
|
try {
|
|
@@ -270,6 +270,7 @@ export class AccessPointLambdaEditorState extends LambdaEditorState {
|
|
|
270
270
|
)) as RawLambda;
|
|
271
271
|
this.setParserError(undefined);
|
|
272
272
|
this.val.accessPoint.func = lambda;
|
|
273
|
+
this.lastComputedLambdaString = this.lambdaString;
|
|
273
274
|
} catch (error) {
|
|
274
275
|
assertErrorThrown(error);
|
|
275
276
|
if (error instanceof ParserError) {
|
|
@@ -303,11 +304,12 @@ export class AccessPointLambdaEditorState extends LambdaEditorState {
|
|
|
303
304
|
options?.pretty,
|
|
304
305
|
)) as Map<string, string>;
|
|
305
306
|
const grammarText = isolatedLambdas.get(this.lambdaId);
|
|
306
|
-
|
|
307
|
+
const nextLambdaString =
|
|
307
308
|
grammarText !== undefined
|
|
308
309
|
? this.extractLambdaString(grammarText)
|
|
309
|
-
: ''
|
|
310
|
-
);
|
|
310
|
+
: '';
|
|
311
|
+
this.setLambdaString(nextLambdaString);
|
|
312
|
+
this.lastComputedLambdaString = nextLambdaString || undefined;
|
|
311
313
|
this.clearErrors({
|
|
312
314
|
preserveCompilationError: options?.preserveCompilationError,
|
|
313
315
|
});
|
|
@@ -373,6 +375,7 @@ export class LakehouseAccessPointState extends AccessPointState {
|
|
|
373
375
|
setShowSampleValuesModal: action,
|
|
374
376
|
addRelationElement: action,
|
|
375
377
|
deleteRelationElement: action,
|
|
378
|
+
createAndaddRelationElement: flow,
|
|
376
379
|
// Add observables for lineage
|
|
377
380
|
lineageState: observable,
|
|
378
381
|
setArtifactContent: action,
|
|
@@ -483,7 +486,11 @@ export class LakehouseAccessPointState extends AccessPointState {
|
|
|
483
486
|
return undefined;
|
|
484
487
|
}
|
|
485
488
|
|
|
486
|
-
createAndaddRelationElement(): void {
|
|
489
|
+
*createAndaddRelationElement(): GeneratorFn<void> {
|
|
490
|
+
if (this.lambdaState.lambdaRelationColumns === undefined) {
|
|
491
|
+
yield flowResult(this.lambdaState.updateLambdaRelationColumns());
|
|
492
|
+
}
|
|
493
|
+
|
|
487
494
|
const newElement = new RelationElement();
|
|
488
495
|
newElement.paths = [this.accessPoint.id];
|
|
489
496
|
|
|
@@ -677,6 +684,8 @@ export class AccessPointGroupState {
|
|
|
677
684
|
deleteAccessPoint: action,
|
|
678
685
|
swapAccessPoints: action,
|
|
679
686
|
containsPublicStereotype: computed,
|
|
687
|
+
hasParserError: computed,
|
|
688
|
+
classifications: computed,
|
|
680
689
|
});
|
|
681
690
|
}
|
|
682
691
|
|
|
@@ -684,12 +693,30 @@ export class AccessPointGroupState {
|
|
|
684
693
|
return Boolean(this.accessPointStates.find((e) => e.isRunningProcess));
|
|
685
694
|
}
|
|
686
695
|
|
|
696
|
+
get hasParserError(): boolean {
|
|
697
|
+
return this.accessPointStates.some(
|
|
698
|
+
(apState) =>
|
|
699
|
+
apState instanceof LakehouseAccessPointState &&
|
|
700
|
+
Boolean(apState.lambdaState.parserError),
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
|
|
687
704
|
get containsPublicStereotype(): StereotypeReference | undefined {
|
|
688
705
|
return this.value.stereotypes.find(
|
|
689
706
|
(stereotype) => stereotype.value === this.publicStereotype,
|
|
690
707
|
);
|
|
691
708
|
}
|
|
692
709
|
|
|
710
|
+
get classifications(): string[] {
|
|
711
|
+
const config =
|
|
712
|
+
this.state.editorStore.applicationStore.config.options.dataProductConfig;
|
|
713
|
+
return (
|
|
714
|
+
(this.containsPublicStereotype
|
|
715
|
+
? config?.publicClassifications
|
|
716
|
+
: config?.classifications) ?? []
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
|
|
693
720
|
get publicStereotype(): Stereotype | undefined {
|
|
694
721
|
const publicStereotype =
|
|
695
722
|
this.state.editorStore.applicationStore.config.options.dataProductConfig
|
|
@@ -1084,11 +1111,15 @@ export class DataProductEditorState extends ElementEditorState {
|
|
|
1084
1111
|
purePropertyMapping?.lambdaState.lambdaPrefix &&
|
|
1085
1112
|
grammarText.startsWith(purePropertyMapping.lambdaState.lambdaPrefix)
|
|
1086
1113
|
) {
|
|
1087
|
-
|
|
1088
|
-
purePropertyMapping.lambdaState.extractLambdaString(grammarText)
|
|
1089
|
-
);
|
|
1090
|
-
|
|
1091
|
-
|
|
1114
|
+
const nextLambdaString =
|
|
1115
|
+
purePropertyMapping.lambdaState.extractLambdaString(grammarText);
|
|
1116
|
+
purePropertyMapping.lambdaState.setLambdaString(nextLambdaString);
|
|
1117
|
+
purePropertyMapping.lambdaState.lastComputedLambdaString =
|
|
1118
|
+
nextLambdaString || undefined;
|
|
1119
|
+
} else if (purePropertyMapping) {
|
|
1120
|
+
purePropertyMapping.lambdaState.setLambdaString(grammarText);
|
|
1121
|
+
purePropertyMapping.lambdaState.lastComputedLambdaString =
|
|
1122
|
+
grammarText || undefined;
|
|
1092
1123
|
}
|
|
1093
1124
|
});
|
|
1094
1125
|
} catch (error) {
|
|
@@ -75,6 +75,7 @@ export enum PACKAGEABLE_ELEMENT_TYPE {
|
|
|
75
75
|
MEM_SQL_FUNCTION = 'MEM_SQL_FUNCTION',
|
|
76
76
|
// New Strategical Data Product
|
|
77
77
|
_DATA_PRODUCT = 'BETA_DATA_PRODUCT',
|
|
78
|
+
_COMPUTE = 'BETA_COMPUTE',
|
|
78
79
|
|
|
79
80
|
TEMPORARY__LOCAL_CONNECTION = 'LOCAL_CONNECTION',
|
|
80
81
|
INTERNAL__UnknownElement = 'UNKNOWN',
|