@finos/legend-application-studio 28.21.46 → 28.21.48
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 +8 -0
- package/lib/__lib__/LegendStudioEvent.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioEvent.js +13 -0
- package/lib/__lib__/LegendStudioEvent.js.map +1 -1
- package/lib/__lib__/LegendStudioTelemetryHelper.d.ts +170 -6
- package/lib/__lib__/LegendStudioTelemetryHelper.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioTelemetryHelper.js +116 -1
- package/lib/__lib__/LegendStudioTelemetryHelper.js.map +1 -1
- package/lib/components/editor/editor-group/LegendAISuggestTelemetryHooks.d.ts +30 -0
- package/lib/components/editor/editor-group/LegendAISuggestTelemetryHooks.d.ts.map +1 -0
- package/lib/components/editor/editor-group/LegendAISuggestTelemetryHooks.js +43 -0
- package/lib/components/editor/editor-group/LegendAISuggestTelemetryHooks.js.map +1 -0
- package/lib/components/editor/editor-group/RuntimeEditor.d.ts +4 -3
- package/lib/components/editor/editor-group/RuntimeEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/RuntimeEditor.js +90 -36
- package/lib/components/editor/editor-group/RuntimeEditor.js.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js +154 -35
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataProductQueryBuilderHelper.d.ts.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataProductQueryBuilderHelper.js +4 -6
- package/lib/components/editor/editor-group/dataProduct/DataProductQueryBuilderHelper.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 +31 -7
- package/lib/components/editor/editor-group/service-editor/ServiceEditor.js.map +1 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.js +4 -8
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.d.ts +3 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/EditorStore.d.ts +2 -0
- package/lib/stores/editor/EditorStore.d.ts.map +1 -1
- package/lib/stores/editor/EditorStore.js +2 -0
- package/lib/stores/editor/EditorStore.js.map +1 -1
- package/lib/stores/editor/GraphEditFormModeState.d.ts.map +1 -1
- package/lib/stores/editor/GraphEditFormModeState.js +21 -10
- package/lib/stores/editor/GraphEditFormModeState.js.map +1 -1
- package/lib/stores/editor/LegendAISuggestTelemetry.d.ts +143 -0
- package/lib/stores/editor/LegendAISuggestTelemetry.d.ts.map +1 -0
- package/lib/stores/editor/LegendAISuggestTelemetry.js +376 -0
- package/lib/stores/editor/LegendAISuggestTelemetry.js.map +1 -0
- package/lib/stores/editor/LegendSQLStudioPlaygroundState.js +3 -3
- package/lib/stores/editor/LegendSQLStudioPlaygroundState.js.map +1 -1
- package/lib/stores/editor/editor-state/GraphGenerationState.d.ts +14 -3
- package/lib/stores/editor/editor-state/GraphGenerationState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/GraphGenerationState.js +33 -21
- package/lib/stores/editor/editor-state/GraphGenerationState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/RuntimeEditorState.d.ts +35 -6
- package/lib/stores/editor/editor-state/element-editor-state/RuntimeEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/RuntimeEditorState.js +74 -29
- package/lib/stores/editor/editor-state/element-editor-state/RuntimeEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js +5 -5
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +12 -0
- 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 +60 -14
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +2 -2
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js +34 -15
- package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js +3 -11
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.js +30 -2
- package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/LocalChangesState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/LocalChangesState.js +1 -0
- package/lib/stores/editor/sidebar-state/LocalChangesState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/WorkflowManagerState.d.ts +1 -1
- package/lib/stores/editor/sidebar-state/WorkflowManagerState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/WorkflowManagerState.js +2 -12
- package/lib/stores/editor/sidebar-state/WorkflowManagerState.js.map +1 -1
- package/lib/stores/editor/utils/MockDataUtils.d.ts +12 -2
- package/lib/stores/editor/utils/MockDataUtils.d.ts.map +1 -1
- package/lib/stores/editor/utils/MockDataUtils.js +28 -28
- package/lib/stores/editor/utils/MockDataUtils.js.map +1 -1
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts +2 -0
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js +13 -0
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js.map +1 -1
- package/lib/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.d.ts +20 -2
- package/lib/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.d.ts.map +1 -1
- package/lib/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.js +38 -4
- package/lib/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.js.map +1 -1
- package/package.json +17 -17
- package/src/__lib__/LegendStudioEvent.ts +14 -0
- package/src/__lib__/LegendStudioTelemetryHelper.ts +277 -4
- package/src/components/editor/editor-group/LegendAISuggestTelemetryHooks.ts +57 -0
- package/src/components/editor/editor-group/RuntimeEditor.tsx +282 -132
- package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +293 -106
- package/src/components/editor/editor-group/dataProduct/DataProductQueryBuilderHelper.ts +3 -13
- package/src/components/editor/editor-group/service-editor/ServiceEditor.tsx +41 -23
- package/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx +5 -11
- package/src/index.ts +13 -0
- package/src/stores/editor/EditorStore.ts +3 -0
- package/src/stores/editor/GraphEditFormModeState.ts +31 -15
- package/src/stores/editor/LegendAISuggestTelemetry.ts +592 -0
- package/src/stores/editor/LegendSQLStudioPlaygroundState.ts +3 -3
- package/src/stores/editor/editor-state/GraphGenerationState.ts +48 -42
- package/src/stores/editor/editor-state/element-editor-state/RuntimeEditorState.ts +92 -31
- package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +6 -6
- package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +75 -17
- package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +2 -2
- package/src/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.ts +41 -23
- package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts +12 -21
- package/src/stores/editor/sidebar-state/BulkServiceRegistrationState.ts +49 -6
- package/src/stores/editor/sidebar-state/LocalChangesState.ts +4 -0
- package/src/stores/editor/sidebar-state/WorkflowManagerState.ts +3 -12
- package/src/stores/editor/utils/MockDataUtils.ts +33 -32
- package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +18 -0
- package/src/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.ts +62 -7
- package/tsconfig.json +2 -0
|
@@ -117,7 +117,8 @@ import {
|
|
|
117
117
|
type LakehouseAccessPoint,
|
|
118
118
|
type Mapping,
|
|
119
119
|
type PackageableElement,
|
|
120
|
-
type
|
|
120
|
+
type AccessPointGroup,
|
|
121
|
+
DataProduct,
|
|
121
122
|
DataProductEmbeddedImageIcon,
|
|
122
123
|
DataProductLibraryIcon,
|
|
123
124
|
Email,
|
|
@@ -143,6 +144,8 @@ import {
|
|
|
143
144
|
import {
|
|
144
145
|
accessPoint_setClassification,
|
|
145
146
|
accessPoint_setReproducible,
|
|
147
|
+
accessPointGroup_addTarget,
|
|
148
|
+
accessPointGroup_deleteTarget,
|
|
146
149
|
accessPointGroup_setDescription,
|
|
147
150
|
accessPointGroup_setName,
|
|
148
151
|
dataProduct_setDescription,
|
|
@@ -199,11 +202,17 @@ import type { LegendStudioApplicationStore } from '../../../../stores/LegendStud
|
|
|
199
202
|
import type { DepotServerClient } from '@finos/legend-server-depot';
|
|
200
203
|
import { RelationElementSampleValuesEditor } from '../data-editor/RelationElementSampleValuesEditor.js';
|
|
201
204
|
import type {
|
|
205
|
+
AccessPointGroupMeta,
|
|
202
206
|
AccessPointMeta,
|
|
203
207
|
DataProductDocResponse,
|
|
204
208
|
DSL_DataProduct_LegendStudioApplicationPlugin_Extension,
|
|
205
209
|
} from '../../../../stores/extensions/DSL_DataProduct_LegendStudioApplicationPlugin_Extension.js';
|
|
206
|
-
import {
|
|
210
|
+
import {
|
|
211
|
+
LEGENDAI_SUGGEST_MATCH_STRATEGY,
|
|
212
|
+
LEGENDAI_SUGGEST_STAGE,
|
|
213
|
+
LEGENDAI_SUGGEST_SURFACE,
|
|
214
|
+
} from '../../../../__lib__/LegendStudioTelemetryHelper.js';
|
|
215
|
+
import { useLegendAISuggestTelemetry } from '../LegendAISuggestTelemetryHooks.js';
|
|
207
216
|
import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../../__lib__/LegendStudioDocumentation.js';
|
|
208
217
|
|
|
209
218
|
export enum AP_GROUP_MODAL_ERRORS {
|
|
@@ -542,7 +551,13 @@ export const LakehouseDataProductAccessPointEditor = observer(
|
|
|
542
551
|
};
|
|
543
552
|
|
|
544
553
|
const updateAccessPointTargetEnvironment = action(
|
|
545
|
-
(targetEnvironment: LakehouseTargetEnv) => {
|
|
554
|
+
(targetEnvironment: LakehouseTargetEnv | undefined) => {
|
|
555
|
+
if (
|
|
556
|
+
targetEnvironment !== undefined &&
|
|
557
|
+
groupState.value.targets?.length
|
|
558
|
+
) {
|
|
559
|
+
groupState.value.targets = undefined;
|
|
560
|
+
}
|
|
546
561
|
accessPoint.targetEnvironment = targetEnvironment;
|
|
547
562
|
},
|
|
548
563
|
);
|
|
@@ -811,6 +826,15 @@ export const LakehouseDataProductAccessPointEditor = observer(
|
|
|
811
826
|
className="access-point-editor__dropdown"
|
|
812
827
|
content={
|
|
813
828
|
<MenuContent>
|
|
829
|
+
<MenuContentItem
|
|
830
|
+
className="btn__dropdown-combo__option"
|
|
831
|
+
title="Clear"
|
|
832
|
+
onClick={() =>
|
|
833
|
+
updateAccessPointTargetEnvironment(undefined)
|
|
834
|
+
}
|
|
835
|
+
>
|
|
836
|
+
{' '}
|
|
837
|
+
</MenuContentItem>
|
|
814
838
|
{Object.values(LakehouseTargetEnv).map(
|
|
815
839
|
(environment) => (
|
|
816
840
|
<MenuContentItem
|
|
@@ -1164,6 +1188,43 @@ const AccessPointLoadingSentinel = (props: {
|
|
|
1164
1188
|
ref?: React.Ref<HTMLDivElement>;
|
|
1165
1189
|
}) => <div ref={props.ref} className="access-point-editor__sentinel" />;
|
|
1166
1190
|
|
|
1191
|
+
/**
|
|
1192
|
+
* Finds the suggested metadata for an access point group: by group name
|
|
1193
|
+
* first, falling back to the group's position in the product.
|
|
1194
|
+
*/
|
|
1195
|
+
const matchAccessPointGroupSuggestion = (
|
|
1196
|
+
suggestion: DataProductDocResponse,
|
|
1197
|
+
groupId: string,
|
|
1198
|
+
groupIndex: number,
|
|
1199
|
+
): {
|
|
1200
|
+
groupMeta: AccessPointGroupMeta | undefined;
|
|
1201
|
+
accessPointMetas: AccessPointMeta[];
|
|
1202
|
+
} => {
|
|
1203
|
+
const groupMeta =
|
|
1204
|
+
suggestion.access_point_groups.find((g) => g.name === groupId) ??
|
|
1205
|
+
suggestion.access_point_groups[groupIndex];
|
|
1206
|
+
const accessPointMetas = suggestion.access_points.filter(
|
|
1207
|
+
(ap) => ap.group === (groupMeta?.name ?? groupId),
|
|
1208
|
+
);
|
|
1209
|
+
return { groupMeta, accessPointMetas };
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Flattens the access point group fields a LegendAI suggestion writes so the
|
|
1214
|
+
* applied value can be compared with what is eventually pushed.
|
|
1215
|
+
*/
|
|
1216
|
+
const serializeAccessPointGroupAppliedFields = (
|
|
1217
|
+
group: AccessPointGroup,
|
|
1218
|
+
accessPointCount: number,
|
|
1219
|
+
): string =>
|
|
1220
|
+
[
|
|
1221
|
+
group.title ?? '',
|
|
1222
|
+
group.description ?? '',
|
|
1223
|
+
...group.accessPoints
|
|
1224
|
+
.slice(0, accessPointCount)
|
|
1225
|
+
.flatMap((ap) => [ap.id, ap.title ?? '', ap.description ?? '']),
|
|
1226
|
+
].join('\n');
|
|
1227
|
+
|
|
1167
1228
|
const AccessPointGroupEditor = observer(
|
|
1168
1229
|
(props: { groupState: AccessPointGroupState; isReadOnly: boolean }) => {
|
|
1169
1230
|
const { groupState, isReadOnly } = props;
|
|
@@ -1275,6 +1336,31 @@ const AccessPointGroupEditor = observer(
|
|
|
1275
1336
|
accessPointGroup_setTitle(groupState.value, val);
|
|
1276
1337
|
};
|
|
1277
1338
|
|
|
1339
|
+
const getTargetEnvironmentOptions = () => {
|
|
1340
|
+
const existingTargets = groupState.value.targets ?? [];
|
|
1341
|
+
return Object.values(LakehouseTargetEnv)
|
|
1342
|
+
.filter((target) => !existingTargets.includes(target))
|
|
1343
|
+
.map((target) => ({
|
|
1344
|
+
label: target,
|
|
1345
|
+
value: target,
|
|
1346
|
+
}));
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
const handleAddTargetEnvironment = action(
|
|
1350
|
+
(val: { label: string; value: LakehouseTargetEnv } | null): void => {
|
|
1351
|
+
if (val) {
|
|
1352
|
+
accessPointGroup_addTarget(groupState.value, val.value);
|
|
1353
|
+
lakehouseAccessPointStates.forEach((accessPointState) => {
|
|
1354
|
+
accessPointState.accessPoint.targetEnvironment = undefined;
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
},
|
|
1358
|
+
);
|
|
1359
|
+
|
|
1360
|
+
const handleRemoveTargetEnvironment = (target: string) => {
|
|
1361
|
+
accessPointGroup_deleteTarget(groupState.value, target);
|
|
1362
|
+
};
|
|
1363
|
+
|
|
1278
1364
|
// AI suggestion for APG
|
|
1279
1365
|
const legendAIUrl = editorStore.applicationStore.config.legendAIUrl;
|
|
1280
1366
|
const aiDocSuggester = legendAIUrl
|
|
@@ -1287,38 +1373,71 @@ const AccessPointGroupEditor = observer(
|
|
|
1287
1373
|
)
|
|
1288
1374
|
.find(Boolean)
|
|
1289
1375
|
: undefined;
|
|
1376
|
+
const aiSuggestTelemetry = useLegendAISuggestTelemetry(
|
|
1377
|
+
editorStore,
|
|
1378
|
+
{
|
|
1379
|
+
surface: LEGENDAI_SUGGEST_SURFACE.DATA_PRODUCT,
|
|
1380
|
+
elementPath: productEditorState.product.path,
|
|
1381
|
+
accessPointGroupId: groupState.value.id,
|
|
1382
|
+
},
|
|
1383
|
+
{ legendAIUrl, available: Boolean(aiDocSuggester), isReadOnly },
|
|
1384
|
+
);
|
|
1290
1385
|
const suggestWithAI = async (): Promise<void> => {
|
|
1291
1386
|
if (!aiDocSuggester || !legendAIUrl) {
|
|
1292
1387
|
return;
|
|
1293
1388
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
);
|
|
1389
|
+
const request = aiSuggestTelemetry.launch({
|
|
1390
|
+
existingText: groupState.value.description,
|
|
1391
|
+
accessPointCount: groupState.value.accessPoints.length,
|
|
1392
|
+
});
|
|
1299
1393
|
setIsSuggestingWithAI(true);
|
|
1300
1394
|
setAISuggestion(undefined);
|
|
1395
|
+
let stage = LEGENDAI_SUGGEST_STAGE.SERIALIZE;
|
|
1301
1396
|
try {
|
|
1302
1397
|
const definitions =
|
|
1303
1398
|
await editorStore.graphManagerState.graphManager.graphToPureCode(
|
|
1304
1399
|
editorStore.graphManagerState.graph,
|
|
1305
1400
|
);
|
|
1401
|
+
stage = LEGENDAI_SUGGEST_STAGE.REQUEST;
|
|
1306
1402
|
const product = productEditorState.product;
|
|
1307
1403
|
const suggestion = await aiDocSuggester(
|
|
1308
1404
|
{ definitions, data_product_name: product.path },
|
|
1309
1405
|
legendAIUrl,
|
|
1310
1406
|
);
|
|
1407
|
+
const { groupMeta, accessPointMetas } = matchAccessPointGroupSuggestion(
|
|
1408
|
+
suggestion,
|
|
1409
|
+
groupState.value.id,
|
|
1410
|
+
productEditorState.accessPointGroupStates.indexOf(groupState),
|
|
1411
|
+
);
|
|
1412
|
+
const shouldShow = aiSuggestTelemetry.succeed(request, {
|
|
1413
|
+
// the response is structured, so measure the parts shown for this group
|
|
1414
|
+
suggestionText: [
|
|
1415
|
+
groupMeta?.title,
|
|
1416
|
+
groupMeta?.description,
|
|
1417
|
+
...accessPointMetas.flatMap((ap) => [
|
|
1418
|
+
ap.name,
|
|
1419
|
+
ap.title,
|
|
1420
|
+
ap.description,
|
|
1421
|
+
]),
|
|
1422
|
+
]
|
|
1423
|
+
.filter(Boolean)
|
|
1424
|
+
.join('\n'),
|
|
1425
|
+
definitionsLength: definitions.length,
|
|
1426
|
+
currentText: groupState.value.description,
|
|
1427
|
+
confidence: groupMeta?.confidence,
|
|
1428
|
+
accessPointSuggestionCount: accessPointMetas.length,
|
|
1429
|
+
});
|
|
1430
|
+
if (!shouldShow) {
|
|
1431
|
+
editorStore.applicationStore.notificationService.notifyWarning(
|
|
1432
|
+
`LegendAI did not return a suggestion for access point group '${groupState.value.id}'`,
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1311
1435
|
runInAction(() => {
|
|
1312
|
-
setAISuggestion(suggestion);
|
|
1436
|
+
setAISuggestion(shouldShow ? suggestion : undefined);
|
|
1313
1437
|
});
|
|
1314
1438
|
} catch (error) {
|
|
1315
1439
|
assertErrorThrown(error);
|
|
1316
|
-
|
|
1317
|
-
editorStore.applicationStore.telemetryService,
|
|
1318
|
-
productEditorState.product.path,
|
|
1319
|
-
error.message,
|
|
1320
|
-
editorStore.editorMode.getSourceInfo(),
|
|
1321
|
-
);
|
|
1440
|
+
aiSuggestTelemetry.fail(request, error, stage);
|
|
1322
1441
|
if (
|
|
1323
1442
|
error instanceof NetworkClientError &&
|
|
1324
1443
|
(error.response.status === HttpStatus.UNAUTHORIZED ||
|
|
@@ -1343,67 +1462,98 @@ const AccessPointGroupEditor = observer(
|
|
|
1343
1462
|
if (!aiSuggestion) {
|
|
1344
1463
|
return;
|
|
1345
1464
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
productEditorState.product.path,
|
|
1349
|
-
editorStore.editorMode.getSourceInfo(),
|
|
1350
|
-
);
|
|
1465
|
+
const group = groupState.value;
|
|
1466
|
+
const existingText = group.description;
|
|
1351
1467
|
// Find matching group in the response
|
|
1352
|
-
const
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
(
|
|
1357
|
-
) ?? aiSuggestion.access_point_groups[gIdx];
|
|
1358
|
-
if (groupMeta) {
|
|
1359
|
-
accessPointGroup_setTitle(groupState.value, groupMeta.title);
|
|
1360
|
-
accessPointGroup_setDescription(
|
|
1361
|
-
groupState.value,
|
|
1362
|
-
groupMeta.description,
|
|
1468
|
+
const { groupMeta, accessPointMetas: apMetas } =
|
|
1469
|
+
matchAccessPointGroupSuggestion(
|
|
1470
|
+
aiSuggestion,
|
|
1471
|
+
group.id,
|
|
1472
|
+
productEditorState.accessPointGroupStates.indexOf(groupState),
|
|
1363
1473
|
);
|
|
1474
|
+
const matchStrategy = !groupMeta
|
|
1475
|
+
? LEGENDAI_SUGGEST_MATCH_STRATEGY.NONE
|
|
1476
|
+
: groupMeta.name === group.id
|
|
1477
|
+
? LEGENDAI_SUGGEST_MATCH_STRATEGY.NAME
|
|
1478
|
+
: LEGENDAI_SUGGEST_MATCH_STRATEGY.INDEX;
|
|
1479
|
+
if (groupMeta) {
|
|
1480
|
+
accessPointGroup_setTitle(group, groupMeta.title);
|
|
1481
|
+
accessPointGroup_setDescription(group, groupMeta.description);
|
|
1364
1482
|
}
|
|
1365
1483
|
// Apply access point metadata for this group
|
|
1366
|
-
const
|
|
1367
|
-
|
|
1484
|
+
const accessPointsUpdated = Math.min(
|
|
1485
|
+
apMetas.length,
|
|
1486
|
+
group.accessPoints.length,
|
|
1368
1487
|
);
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
j++
|
|
1373
|
-
) {
|
|
1488
|
+
let accessPointsRenamed = 0;
|
|
1489
|
+
let namesSanitized = 0;
|
|
1490
|
+
for (let j = 0; j < accessPointsUpdated; j++) {
|
|
1374
1491
|
const apMeta = apMetas[j] as (typeof apMetas)[number];
|
|
1375
|
-
const ap =
|
|
1376
|
-
j
|
|
1377
|
-
] as (typeof groupState.value.accessPoints)[number];
|
|
1492
|
+
const ap = group.accessPoints[j] as (typeof group.accessPoints)[number];
|
|
1378
1493
|
// Convert suggested name to valid identifier (alphanumeric + underscore)
|
|
1379
1494
|
const sanitizedName = apMeta.name.replace(/[^0-9a-zA-Z_]/g, '_');
|
|
1495
|
+
if (sanitizedName !== apMeta.name) {
|
|
1496
|
+
namesSanitized++;
|
|
1497
|
+
}
|
|
1380
1498
|
if (sanitizedName) {
|
|
1499
|
+
if (ap.id !== sanitizedName) {
|
|
1500
|
+
accessPointsRenamed++;
|
|
1501
|
+
}
|
|
1381
1502
|
ap.id = sanitizedName;
|
|
1382
1503
|
}
|
|
1383
1504
|
accessPoint_setTitle(ap, apMeta.title);
|
|
1384
1505
|
accessPoint_setDescription(ap, apMeta.description);
|
|
1385
1506
|
}
|
|
1507
|
+
const productPath = productEditorState.product.path;
|
|
1508
|
+
const groupId = group.id;
|
|
1509
|
+
aiSuggestTelemetry.apply({
|
|
1510
|
+
existingText,
|
|
1511
|
+
appliedText:
|
|
1512
|
+
groupMeta || accessPointsUpdated
|
|
1513
|
+
? serializeAccessPointGroupAppliedFields(group, accessPointsUpdated)
|
|
1514
|
+
: '',
|
|
1515
|
+
readCurrentText: (store) => {
|
|
1516
|
+
const element =
|
|
1517
|
+
store.graphManagerState.graph.getNullableElement(productPath);
|
|
1518
|
+
const currentGroup =
|
|
1519
|
+
element instanceof DataProduct
|
|
1520
|
+
? element.accessPointGroups.find((g) => g.id === groupId)
|
|
1521
|
+
: undefined;
|
|
1522
|
+
return currentGroup
|
|
1523
|
+
? {
|
|
1524
|
+
found: true,
|
|
1525
|
+
text: serializeAccessPointGroupAppliedFields(
|
|
1526
|
+
currentGroup,
|
|
1527
|
+
accessPointsUpdated,
|
|
1528
|
+
),
|
|
1529
|
+
}
|
|
1530
|
+
: { found: false };
|
|
1531
|
+
},
|
|
1532
|
+
dataProduct: {
|
|
1533
|
+
matchStrategy,
|
|
1534
|
+
accessPointsUpdated,
|
|
1535
|
+
accessPointsRenamed,
|
|
1536
|
+
namesSanitized,
|
|
1537
|
+
accessPointCountMismatch:
|
|
1538
|
+
apMetas.length !== group.accessPoints.length,
|
|
1539
|
+
},
|
|
1540
|
+
});
|
|
1386
1541
|
setAISuggestion(undefined);
|
|
1387
1542
|
};
|
|
1388
1543
|
const discardAISuggestion = (): void => {
|
|
1389
|
-
|
|
1390
|
-
editorStore.applicationStore.telemetryService,
|
|
1391
|
-
productEditorState.product.path,
|
|
1392
|
-
editorStore.editorMode.getSourceInfo(),
|
|
1393
|
-
);
|
|
1544
|
+
aiSuggestTelemetry.discard();
|
|
1394
1545
|
setAISuggestion(undefined);
|
|
1395
1546
|
};
|
|
1396
1547
|
|
|
1397
1548
|
// Computed AI suggestion for current group
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
);
|
|
1549
|
+
const { groupMeta: aiGroupMeta, accessPointMetas: aiAccessPointMetas } =
|
|
1550
|
+
aiSuggestion
|
|
1551
|
+
? matchAccessPointGroupSuggestion(
|
|
1552
|
+
aiSuggestion,
|
|
1553
|
+
groupState.value.id,
|
|
1554
|
+
productEditorState.accessPointGroupStates.indexOf(groupState),
|
|
1555
|
+
)
|
|
1556
|
+
: { groupMeta: undefined, accessPointMetas: undefined };
|
|
1407
1557
|
|
|
1408
1558
|
const handleRemoveAccessPointGroup = (): void => {
|
|
1409
1559
|
editorStore.applicationStore.alertService.setActionAlertInfo({
|
|
@@ -1630,6 +1780,47 @@ const AccessPointGroupEditor = observer(
|
|
|
1630
1780
|
</div>
|
|
1631
1781
|
)}
|
|
1632
1782
|
</div>
|
|
1783
|
+
<div className="data-product-editor__operational-input data-product-editor__apg-targets-input">
|
|
1784
|
+
<div
|
|
1785
|
+
className="panel__content__form__section__header__label"
|
|
1786
|
+
style={{ justifyContent: 'space-between', width: '45rem' }}
|
|
1787
|
+
>
|
|
1788
|
+
Target Environments
|
|
1789
|
+
</div>
|
|
1790
|
+
<div className="panel__content__form__section__header__prompt">
|
|
1791
|
+
Select where this Data Product will be deployed.
|
|
1792
|
+
</div>
|
|
1793
|
+
<div className="panel__content__form__section__list__id-list">
|
|
1794
|
+
{groupState.value.targets?.map((target) => (
|
|
1795
|
+
<div
|
|
1796
|
+
className="panel__content__form__section__list__item"
|
|
1797
|
+
key={target}
|
|
1798
|
+
>
|
|
1799
|
+
{target}
|
|
1800
|
+
<button
|
|
1801
|
+
className="panel__content__form__section__list__item__remove-btn"
|
|
1802
|
+
disabled={isReadOnly}
|
|
1803
|
+
onClick={() => handleRemoveTargetEnvironment(target)}
|
|
1804
|
+
tabIndex={-1}
|
|
1805
|
+
title="Remove Target Environment"
|
|
1806
|
+
>
|
|
1807
|
+
<TimesIcon />
|
|
1808
|
+
</button>
|
|
1809
|
+
</div>
|
|
1810
|
+
))}
|
|
1811
|
+
</div>
|
|
1812
|
+
<CustomSelectorInput
|
|
1813
|
+
className="panel__content__form__section__dropdown"
|
|
1814
|
+
options={getTargetEnvironmentOptions()}
|
|
1815
|
+
onChange={handleAddTargetEnvironment}
|
|
1816
|
+
placeholder={'Add Target Environment...'}
|
|
1817
|
+
darkMode={
|
|
1818
|
+
!productEditorState.editorStore.applicationStore.layoutService
|
|
1819
|
+
.TEMPORARY__isLightColorThemeEnabled
|
|
1820
|
+
}
|
|
1821
|
+
disabled={isReadOnly}
|
|
1822
|
+
/>
|
|
1823
|
+
</div>
|
|
1633
1824
|
{editorStore.applicationStore.config.options.dataProductConfig && (
|
|
1634
1825
|
<AccessPointGroupPublicToggle groupState={groupState} />
|
|
1635
1826
|
)}
|
|
@@ -2375,28 +2566,26 @@ const HomeTab = observer(
|
|
|
2375
2566
|
<div className="panel__content__form__section__header__prompt">
|
|
2376
2567
|
Select if this Data Product is Internal or External
|
|
2377
2568
|
</div>
|
|
2378
|
-
<
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2569
|
+
<CustomSelectorInput
|
|
2570
|
+
className="panel__content__form__section__dropdown"
|
|
2571
|
+
options={DATA_PRODUCT_TYPE_OPTIONS}
|
|
2572
|
+
onChange={handleDataProductTypeChange}
|
|
2573
|
+
value={
|
|
2574
|
+
product.type instanceof InternalDataProductType
|
|
2575
|
+
? DATA_PRODUCT_TYPE_OPTIONS.find(
|
|
2576
|
+
(option) => option.value === DATA_PRODUCT_TYPE.INTERNAL,
|
|
2577
|
+
)
|
|
2578
|
+
: product.type instanceof ExternalDataProductType
|
|
2384
2579
|
? DATA_PRODUCT_TYPE_OPTIONS.find(
|
|
2385
|
-
(option) => option.value === DATA_PRODUCT_TYPE.
|
|
2580
|
+
(option) => option.value === DATA_PRODUCT_TYPE.EXTERNAL,
|
|
2386
2581
|
)
|
|
2387
|
-
:
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
darkMode={
|
|
2395
|
-
!dataProductEditorState.editorStore.applicationStore
|
|
2396
|
-
.layoutService.TEMPORARY__isLightColorThemeEnabled
|
|
2397
|
-
}
|
|
2398
|
-
/>
|
|
2399
|
-
</div>
|
|
2582
|
+
: null
|
|
2583
|
+
}
|
|
2584
|
+
darkMode={
|
|
2585
|
+
!dataProductEditorState.editorStore.applicationStore
|
|
2586
|
+
.layoutService.TEMPORARY__isLightColorThemeEnabled
|
|
2587
|
+
}
|
|
2588
|
+
/>
|
|
2400
2589
|
{product.type instanceof ExternalDataProductType && (
|
|
2401
2590
|
<div className="data-product-editor__external-link">
|
|
2402
2591
|
<div className="panel__content__form__section__header__prompt">
|
|
@@ -2994,15 +3183,14 @@ const OperationalTab = observer(
|
|
|
2994
3183
|
</div>
|
|
2995
3184
|
))}
|
|
2996
3185
|
</div>
|
|
2997
|
-
<
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
</div>
|
|
3186
|
+
<CustomSelectorInput<EnumOption<Region>>
|
|
3187
|
+
className="panel__content__form__section__dropdown"
|
|
3188
|
+
options={getCoverageRegionOptions()}
|
|
3189
|
+
onChange={handleAddRegion}
|
|
3190
|
+
placeholder={CHOOSE_REGION}
|
|
3191
|
+
darkMode={true}
|
|
3192
|
+
disabled={isReadOnly}
|
|
3193
|
+
/>
|
|
3006
3194
|
</div>
|
|
3007
3195
|
<div className="data-product-editor__operational-input">
|
|
3008
3196
|
<div
|
|
@@ -3014,28 +3202,27 @@ const OperationalTab = observer(
|
|
|
3014
3202
|
<div className="panel__content__form__section__header__prompt">
|
|
3015
3203
|
Select the update frequency of this Data Product.
|
|
3016
3204
|
</div>
|
|
3017
|
-
<
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
</div>
|
|
3205
|
+
<CustomSelectorInput<EnumOption<DeliveryFrequency>>
|
|
3206
|
+
className="panel__content__form__section__dropdown"
|
|
3207
|
+
options={(
|
|
3208
|
+
Object.values(DeliveryFrequency) as DeliveryFrequency[]
|
|
3209
|
+
).map((frequency) => ({
|
|
3210
|
+
label: frequency,
|
|
3211
|
+
value: frequency,
|
|
3212
|
+
}))}
|
|
3213
|
+
onChange={handleUpdateFrequencyChange}
|
|
3214
|
+
value={
|
|
3215
|
+
product.operationalMetadata?.updateFrequency
|
|
3216
|
+
? {
|
|
3217
|
+
label: product.operationalMetadata.updateFrequency,
|
|
3218
|
+
value: product.operationalMetadata.updateFrequency,
|
|
3219
|
+
}
|
|
3220
|
+
: null
|
|
3221
|
+
}
|
|
3222
|
+
placeholder="Select update frequency..."
|
|
3223
|
+
darkMode={true}
|
|
3224
|
+
disabled={isReadOnly}
|
|
3225
|
+
/>
|
|
3039
3226
|
</div>
|
|
3040
3227
|
</div>
|
|
3041
3228
|
);
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
import {
|
|
18
18
|
type DataProduct,
|
|
19
19
|
type DataProductAccessor,
|
|
20
|
-
type NativeModelExecutionContext,
|
|
21
20
|
LakehouseAccessPoint,
|
|
22
21
|
ModelAccessPointGroup,
|
|
23
22
|
} from '@finos/legend-graph';
|
|
@@ -39,9 +38,6 @@ import {
|
|
|
39
38
|
|
|
40
39
|
const isQueryableDataProduct = (dataProduct: DataProduct): boolean => {
|
|
41
40
|
return (
|
|
42
|
-
Boolean(
|
|
43
|
-
dataProduct.nativeModelAccess?.nativeModelExecutionContexts.length,
|
|
44
|
-
) ||
|
|
45
41
|
dataProduct.accessPointGroups.filter(filterByType(ModelAccessPointGroup))
|
|
46
42
|
.length > 0 ||
|
|
47
43
|
dataProduct.accessPointGroups
|
|
@@ -53,13 +49,7 @@ const isQueryableDataProduct = (dataProduct: DataProduct): boolean => {
|
|
|
53
49
|
|
|
54
50
|
const resolveDefaultExecState = (
|
|
55
51
|
dataProduct: DataProduct,
|
|
56
|
-
):
|
|
57
|
-
| ModelAccessPointGroup
|
|
58
|
-
| LakehouseAccessPoint
|
|
59
|
-
| NativeModelExecutionContext
|
|
60
|
-
| undefined => {
|
|
61
|
-
const nativeAccessPoints =
|
|
62
|
-
dataProduct.nativeModelAccess?.defaultExecutionContext;
|
|
52
|
+
): ModelAccessPointGroup | LakehouseAccessPoint | undefined => {
|
|
63
53
|
const modeled = dataProduct.accessPointGroups.filter(
|
|
64
54
|
filterByType(ModelAccessPointGroup),
|
|
65
55
|
)[0];
|
|
@@ -67,7 +57,7 @@ const resolveDefaultExecState = (
|
|
|
67
57
|
.map((group) => group.accessPoints)
|
|
68
58
|
.flat()
|
|
69
59
|
.filter(filterByType(LakehouseAccessPoint))[0];
|
|
70
|
-
return modeled ?? lakehouseAccessPoints
|
|
60
|
+
return modeled ?? lakehouseAccessPoints;
|
|
71
61
|
};
|
|
72
62
|
|
|
73
63
|
export const queryDataProduct = async (
|
|
@@ -77,7 +67,7 @@ export const queryDataProduct = async (
|
|
|
77
67
|
try {
|
|
78
68
|
assertTrue(
|
|
79
69
|
isQueryableDataProduct(dataProduct),
|
|
80
|
-
'Data Product is not queryable. Data Product must have either a lakehouse
|
|
70
|
+
'Data Product is not queryable. Data Product must have either a lakehouse or model access point',
|
|
81
71
|
);
|
|
82
72
|
const embeddedQueryBuilderState = editorStore.embeddedQueryBuilderState;
|
|
83
73
|
const defaultExecutionContext = guaranteeNonNullable(
|