@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
|
@@ -25,8 +25,8 @@ import { action, autorun, flowResult, runInAction } from 'mobx';
|
|
|
25
25
|
import { DataProductTestableEditor } from './testable/DataProductTestableEditor.js';
|
|
26
26
|
import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
|
|
27
27
|
import { CodeEditor } from '@finos/legend-lego/code-editor';
|
|
28
|
-
import { DataProductEmbeddedImageIcon, DataProductLibraryIcon, Email, LakehouseTargetEnv, StereotypeExplicitReference, V1_DataProduct, V1_DataProductIconLibraryId, V1_PureGraphManager, V1_RemoteEngine, validate_PureExecutionMapping, InternalDataProductType, ExternalDataProductType, DataProductLink, observer_DataProductLink, Region, DeliveryFrequency, AppDirOwner, AppDirNode, observe_AppDirOwner, observe_AppDirNode, AppDirLevel, } from '@finos/legend-graph';
|
|
29
|
-
import { accessPoint_setClassification, accessPoint_setReproducible, accessPointGroup_setDescription, accessPointGroup_setName, dataProduct_setDescription, dataProduct_setIcon, dataProduct_setSupportInfoIfAbsent, dataProduct_setTitle, supportInfo_addEmail, supportInfo_deleteEmail, supportInfo_setDocumentationUrl, supportInfo_setFaqUrl, supportInfo_setLinkLabel, supportInfo_setSupportUrl, supportInfo_setWebsite, dataProduct_setType, expertise_setDescription, expertise_addId, expertise_deleteId, supportInfo_deleteExpertise, externalType_setLinkURL, externalType_setLinkLabel, accessPointGroup_setTitle, accessPoint_setDescription, accessPoint_setTitle, dataProduct_setOperationalMetadataIfAbsent, operationalMetadata_deleteCoverageRegion, operationalMetadata_addCoverageRegion, operationalMetadata_setUpdateFrequency, dataProduct_setOwner, appDirOwner_setProduction, appDirOwner_setProdParallel, appDirNode_setAppDirId, } from '../../../../stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
|
|
28
|
+
import { DataProduct, DataProductEmbeddedImageIcon, DataProductLibraryIcon, Email, LakehouseTargetEnv, StereotypeExplicitReference, V1_DataProduct, V1_DataProductIconLibraryId, V1_PureGraphManager, V1_RemoteEngine, validate_PureExecutionMapping, InternalDataProductType, ExternalDataProductType, DataProductLink, observer_DataProductLink, Region, DeliveryFrequency, AppDirOwner, AppDirNode, observe_AppDirOwner, observe_AppDirNode, AppDirLevel, } from '@finos/legend-graph';
|
|
29
|
+
import { accessPoint_setClassification, accessPoint_setReproducible, accessPointGroup_addTarget, accessPointGroup_deleteTarget, accessPointGroup_setDescription, accessPointGroup_setName, dataProduct_setDescription, dataProduct_setIcon, dataProduct_setSupportInfoIfAbsent, dataProduct_setTitle, supportInfo_addEmail, supportInfo_deleteEmail, supportInfo_setDocumentationUrl, supportInfo_setFaqUrl, supportInfo_setLinkLabel, supportInfo_setSupportUrl, supportInfo_setWebsite, dataProduct_setType, expertise_setDescription, expertise_addId, expertise_deleteId, supportInfo_deleteExpertise, externalType_setLinkURL, externalType_setLinkLabel, accessPointGroup_setTitle, accessPoint_setDescription, accessPoint_setTitle, dataProduct_setOperationalMetadataIfAbsent, operationalMetadata_deleteCoverageRegion, operationalMetadata_addCoverageRegion, operationalMetadata_setUpdateFrequency, dataProduct_setOwner, appDirOwner_setProduction, appDirOwner_setProdParallel, appDirNode_setAppDirId, } from '../../../../stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
|
|
30
30
|
import { LEGEND_STUDIO_TEST_ID } from '../../../../__lib__/LegendStudioTesting.js';
|
|
31
31
|
import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../../__lib__/LegendStudioApplicationNavigationContext.js';
|
|
32
32
|
import { ActionAlertActionType, ActionAlertType, useApplicationNavigationContext, } from '@finos/legend-application';
|
|
@@ -35,7 +35,8 @@ import { annotatedElement_addStereotype, annotatedElement_deleteStereotype, } fr
|
|
|
35
35
|
import { buildElementOption, } from '@finos/legend-lego/graph-editor';
|
|
36
36
|
import { DataProductViewerState, ProductViewer, } from '@finos/legend-extension-dsl-data-product';
|
|
37
37
|
import { RelationElementSampleValuesEditor } from '../data-editor/RelationElementSampleValuesEditor.js';
|
|
38
|
-
import {
|
|
38
|
+
import { LEGENDAI_SUGGEST_MATCH_STRATEGY, LEGENDAI_SUGGEST_STAGE, LEGENDAI_SUGGEST_SURFACE, } from '../../../../__lib__/LegendStudioTelemetryHelper.js';
|
|
39
|
+
import { useLegendAISuggestTelemetry } from '../LegendAISuggestTelemetryHooks.js';
|
|
39
40
|
import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../../__lib__/LegendStudioDocumentation.js';
|
|
40
41
|
export var AP_GROUP_MODAL_ERRORS;
|
|
41
42
|
(function (AP_GROUP_MODAL_ERRORS) {
|
|
@@ -171,6 +172,10 @@ export const LakehouseDataProductAccessPointEditor = observer((props) => {
|
|
|
171
172
|
setIsHoveringTitle(false);
|
|
172
173
|
};
|
|
173
174
|
const updateAccessPointTargetEnvironment = action((targetEnvironment) => {
|
|
175
|
+
if (targetEnvironment !== undefined &&
|
|
176
|
+
groupState.value.targets?.length) {
|
|
177
|
+
groupState.value.targets = undefined;
|
|
178
|
+
}
|
|
174
179
|
accessPoint.targetEnvironment = targetEnvironment;
|
|
175
180
|
});
|
|
176
181
|
const debugPlanGeneration = editorStore.applicationStore.guardUnhandledError(() => flowResult(accessPointState.generateArtifact()));
|
|
@@ -286,7 +291,7 @@ export const LakehouseDataProductAccessPointEditor = observer((props) => {
|
|
|
286
291
|
}
|
|
287
292
|
: undefined;
|
|
288
293
|
})(), deleteConfirmMessage: `Are you sure you want to delete sample values for Access Point ${accessPointState.accessPoint.id}?`, onAdd: () => flowResult(accessPointState.createAndaddRelationElement()), onDelete: () => accessPointState.deleteRelationElement() }), editorStore.applicationStore.config.options
|
|
289
|
-
.dataProductConfig && (_jsx(AccessPointClassification, { accessPoint: accessPoint, groupState: groupState })), _jsxs("div", { className: clsx('access-point-editor__type'), title: 'Change target environment', children: [_jsx("div", { className: "access-point-editor__type__label", children: accessPoint.targetEnvironment }), _jsx(ControlledDropdownMenu, { className: "access-point-editor__dropdown", content:
|
|
294
|
+
.dataProductConfig && (_jsx(AccessPointClassification, { accessPoint: accessPoint, groupState: groupState })), _jsxs("div", { className: clsx('access-point-editor__type'), title: 'Change target environment', children: [_jsx("div", { className: "access-point-editor__type__label", children: accessPoint.targetEnvironment }), _jsx(ControlledDropdownMenu, { className: "access-point-editor__dropdown", content: _jsxs(MenuContent, { children: [_jsx(MenuContentItem, { className: "btn__dropdown-combo__option", title: "Clear", onClick: () => updateAccessPointTargetEnvironment(undefined), children: ' ' }), Object.values(LakehouseTargetEnv).map((environment) => (_jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: () => updateAccessPointTargetEnvironment(environment), children: environment }, environment)))] }), menuProps: {
|
|
290
295
|
anchorOrigin: {
|
|
291
296
|
vertical: 'bottom',
|
|
292
297
|
horizontal: 'right',
|
|
@@ -376,6 +381,27 @@ const ModelAccessPointGroupEditor = observer((props) => {
|
|
|
376
381
|
}, tabIndex: -1, title: "See mapping", disabled: Boolean(isMappingEmpty), children: _jsx(LongArrowRightIcon, {}) })] })] }));
|
|
377
382
|
});
|
|
378
383
|
const AccessPointLoadingSentinel = (props) => _jsx("div", { ref: props.ref, className: "access-point-editor__sentinel" });
|
|
384
|
+
/**
|
|
385
|
+
* Finds the suggested metadata for an access point group: by group name
|
|
386
|
+
* first, falling back to the group's position in the product.
|
|
387
|
+
*/
|
|
388
|
+
const matchAccessPointGroupSuggestion = (suggestion, groupId, groupIndex) => {
|
|
389
|
+
const groupMeta = suggestion.access_point_groups.find((g) => g.name === groupId) ??
|
|
390
|
+
suggestion.access_point_groups[groupIndex];
|
|
391
|
+
const accessPointMetas = suggestion.access_points.filter((ap) => ap.group === (groupMeta?.name ?? groupId));
|
|
392
|
+
return { groupMeta, accessPointMetas };
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* Flattens the access point group fields a LegendAI suggestion writes so the
|
|
396
|
+
* applied value can be compared with what is eventually pushed.
|
|
397
|
+
*/
|
|
398
|
+
const serializeAccessPointGroupAppliedFields = (group, accessPointCount) => [
|
|
399
|
+
group.title ?? '',
|
|
400
|
+
group.description ?? '',
|
|
401
|
+
...group.accessPoints
|
|
402
|
+
.slice(0, accessPointCount)
|
|
403
|
+
.flatMap((ap) => [ap.id, ap.title ?? '', ap.description ?? '']),
|
|
404
|
+
].join('\n');
|
|
379
405
|
const AccessPointGroupEditor = observer((props) => {
|
|
380
406
|
const { groupState, isReadOnly } = props;
|
|
381
407
|
const editorStore = useEditorStore();
|
|
@@ -460,6 +486,26 @@ const AccessPointGroupEditor = observer((props) => {
|
|
|
460
486
|
const updateGroupTitle = (val) => {
|
|
461
487
|
accessPointGroup_setTitle(groupState.value, val);
|
|
462
488
|
};
|
|
489
|
+
const getTargetEnvironmentOptions = () => {
|
|
490
|
+
const existingTargets = groupState.value.targets ?? [];
|
|
491
|
+
return Object.values(LakehouseTargetEnv)
|
|
492
|
+
.filter((target) => !existingTargets.includes(target))
|
|
493
|
+
.map((target) => ({
|
|
494
|
+
label: target,
|
|
495
|
+
value: target,
|
|
496
|
+
}));
|
|
497
|
+
};
|
|
498
|
+
const handleAddTargetEnvironment = action((val) => {
|
|
499
|
+
if (val) {
|
|
500
|
+
accessPointGroup_addTarget(groupState.value, val.value);
|
|
501
|
+
lakehouseAccessPointStates.forEach((accessPointState) => {
|
|
502
|
+
accessPointState.accessPoint.targetEnvironment = undefined;
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
const handleRemoveTargetEnvironment = (target) => {
|
|
507
|
+
accessPointGroup_deleteTarget(groupState.value, target);
|
|
508
|
+
};
|
|
463
509
|
// AI suggestion for APG
|
|
464
510
|
const legendAIUrl = editorStore.applicationStore.config.legendAIUrl;
|
|
465
511
|
const aiDocSuggester = legendAIUrl
|
|
@@ -468,24 +514,56 @@ const AccessPointGroupEditor = observer((props) => {
|
|
|
468
514
|
.map((p) => p.getExtraDataProductDocumentationAISuggester?.bind(p))
|
|
469
515
|
.find(Boolean)
|
|
470
516
|
: undefined;
|
|
517
|
+
const aiSuggestTelemetry = useLegendAISuggestTelemetry(editorStore, {
|
|
518
|
+
surface: LEGENDAI_SUGGEST_SURFACE.DATA_PRODUCT,
|
|
519
|
+
elementPath: productEditorState.product.path,
|
|
520
|
+
accessPointGroupId: groupState.value.id,
|
|
521
|
+
}, { legendAIUrl, available: Boolean(aiDocSuggester), isReadOnly });
|
|
471
522
|
const suggestWithAI = async () => {
|
|
472
523
|
if (!aiDocSuggester || !legendAIUrl) {
|
|
473
524
|
return;
|
|
474
525
|
}
|
|
475
|
-
|
|
526
|
+
const request = aiSuggestTelemetry.launch({
|
|
527
|
+
existingText: groupState.value.description,
|
|
528
|
+
accessPointCount: groupState.value.accessPoints.length,
|
|
529
|
+
});
|
|
476
530
|
setIsSuggestingWithAI(true);
|
|
477
531
|
setAISuggestion(undefined);
|
|
532
|
+
let stage = LEGENDAI_SUGGEST_STAGE.SERIALIZE;
|
|
478
533
|
try {
|
|
479
534
|
const definitions = await editorStore.graphManagerState.graphManager.graphToPureCode(editorStore.graphManagerState.graph);
|
|
535
|
+
stage = LEGENDAI_SUGGEST_STAGE.REQUEST;
|
|
480
536
|
const product = productEditorState.product;
|
|
481
537
|
const suggestion = await aiDocSuggester({ definitions, data_product_name: product.path }, legendAIUrl);
|
|
538
|
+
const { groupMeta, accessPointMetas } = matchAccessPointGroupSuggestion(suggestion, groupState.value.id, productEditorState.accessPointGroupStates.indexOf(groupState));
|
|
539
|
+
const shouldShow = aiSuggestTelemetry.succeed(request, {
|
|
540
|
+
// the response is structured, so measure the parts shown for this group
|
|
541
|
+
suggestionText: [
|
|
542
|
+
groupMeta?.title,
|
|
543
|
+
groupMeta?.description,
|
|
544
|
+
...accessPointMetas.flatMap((ap) => [
|
|
545
|
+
ap.name,
|
|
546
|
+
ap.title,
|
|
547
|
+
ap.description,
|
|
548
|
+
]),
|
|
549
|
+
]
|
|
550
|
+
.filter(Boolean)
|
|
551
|
+
.join('\n'),
|
|
552
|
+
definitionsLength: definitions.length,
|
|
553
|
+
currentText: groupState.value.description,
|
|
554
|
+
confidence: groupMeta?.confidence,
|
|
555
|
+
accessPointSuggestionCount: accessPointMetas.length,
|
|
556
|
+
});
|
|
557
|
+
if (!shouldShow) {
|
|
558
|
+
editorStore.applicationStore.notificationService.notifyWarning(`LegendAI did not return a suggestion for access point group '${groupState.value.id}'`);
|
|
559
|
+
}
|
|
482
560
|
runInAction(() => {
|
|
483
|
-
setAISuggestion(suggestion);
|
|
561
|
+
setAISuggestion(shouldShow ? suggestion : undefined);
|
|
484
562
|
});
|
|
485
563
|
}
|
|
486
564
|
catch (error) {
|
|
487
565
|
assertErrorThrown(error);
|
|
488
|
-
|
|
566
|
+
aiSuggestTelemetry.fail(request, error, stage);
|
|
489
567
|
if (error instanceof NetworkClientError &&
|
|
490
568
|
(error.response.status === HttpStatus.UNAUTHORIZED ||
|
|
491
569
|
error.response.status === HttpStatus.FORBIDDEN)) {
|
|
@@ -506,37 +584,77 @@ const AccessPointGroupEditor = observer((props) => {
|
|
|
506
584
|
if (!aiSuggestion) {
|
|
507
585
|
return;
|
|
508
586
|
}
|
|
509
|
-
|
|
587
|
+
const group = groupState.value;
|
|
588
|
+
const existingText = group.description;
|
|
510
589
|
// Find matching group in the response
|
|
511
|
-
const
|
|
512
|
-
const
|
|
590
|
+
const { groupMeta, accessPointMetas: apMetas } = matchAccessPointGroupSuggestion(aiSuggestion, group.id, productEditorState.accessPointGroupStates.indexOf(groupState));
|
|
591
|
+
const matchStrategy = !groupMeta
|
|
592
|
+
? LEGENDAI_SUGGEST_MATCH_STRATEGY.NONE
|
|
593
|
+
: groupMeta.name === group.id
|
|
594
|
+
? LEGENDAI_SUGGEST_MATCH_STRATEGY.NAME
|
|
595
|
+
: LEGENDAI_SUGGEST_MATCH_STRATEGY.INDEX;
|
|
513
596
|
if (groupMeta) {
|
|
514
|
-
accessPointGroup_setTitle(
|
|
515
|
-
accessPointGroup_setDescription(
|
|
597
|
+
accessPointGroup_setTitle(group, groupMeta.title);
|
|
598
|
+
accessPointGroup_setDescription(group, groupMeta.description);
|
|
516
599
|
}
|
|
517
600
|
// Apply access point metadata for this group
|
|
518
|
-
const
|
|
519
|
-
|
|
601
|
+
const accessPointsUpdated = Math.min(apMetas.length, group.accessPoints.length);
|
|
602
|
+
let accessPointsRenamed = 0;
|
|
603
|
+
let namesSanitized = 0;
|
|
604
|
+
for (let j = 0; j < accessPointsUpdated; j++) {
|
|
520
605
|
const apMeta = apMetas[j];
|
|
521
|
-
const ap =
|
|
606
|
+
const ap = group.accessPoints[j];
|
|
522
607
|
// Convert suggested name to valid identifier (alphanumeric + underscore)
|
|
523
608
|
const sanitizedName = apMeta.name.replace(/[^0-9a-zA-Z_]/g, '_');
|
|
609
|
+
if (sanitizedName !== apMeta.name) {
|
|
610
|
+
namesSanitized++;
|
|
611
|
+
}
|
|
524
612
|
if (sanitizedName) {
|
|
613
|
+
if (ap.id !== sanitizedName) {
|
|
614
|
+
accessPointsRenamed++;
|
|
615
|
+
}
|
|
525
616
|
ap.id = sanitizedName;
|
|
526
617
|
}
|
|
527
618
|
accessPoint_setTitle(ap, apMeta.title);
|
|
528
619
|
accessPoint_setDescription(ap, apMeta.description);
|
|
529
620
|
}
|
|
621
|
+
const productPath = productEditorState.product.path;
|
|
622
|
+
const groupId = group.id;
|
|
623
|
+
aiSuggestTelemetry.apply({
|
|
624
|
+
existingText,
|
|
625
|
+
appliedText: groupMeta || accessPointsUpdated
|
|
626
|
+
? serializeAccessPointGroupAppliedFields(group, accessPointsUpdated)
|
|
627
|
+
: '',
|
|
628
|
+
readCurrentText: (store) => {
|
|
629
|
+
const element = store.graphManagerState.graph.getNullableElement(productPath);
|
|
630
|
+
const currentGroup = element instanceof DataProduct
|
|
631
|
+
? element.accessPointGroups.find((g) => g.id === groupId)
|
|
632
|
+
: undefined;
|
|
633
|
+
return currentGroup
|
|
634
|
+
? {
|
|
635
|
+
found: true,
|
|
636
|
+
text: serializeAccessPointGroupAppliedFields(currentGroup, accessPointsUpdated),
|
|
637
|
+
}
|
|
638
|
+
: { found: false };
|
|
639
|
+
},
|
|
640
|
+
dataProduct: {
|
|
641
|
+
matchStrategy,
|
|
642
|
+
accessPointsUpdated,
|
|
643
|
+
accessPointsRenamed,
|
|
644
|
+
namesSanitized,
|
|
645
|
+
accessPointCountMismatch: apMetas.length !== group.accessPoints.length,
|
|
646
|
+
},
|
|
647
|
+
});
|
|
530
648
|
setAISuggestion(undefined);
|
|
531
649
|
};
|
|
532
650
|
const discardAISuggestion = () => {
|
|
533
|
-
|
|
651
|
+
aiSuggestTelemetry.discard();
|
|
534
652
|
setAISuggestion(undefined);
|
|
535
653
|
};
|
|
536
654
|
// Computed AI suggestion for current group
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
655
|
+
const { groupMeta: aiGroupMeta, accessPointMetas: aiAccessPointMetas } = aiSuggestion
|
|
656
|
+
? matchAccessPointGroupSuggestion(aiSuggestion, groupState.value.id, productEditorState.accessPointGroupStates.indexOf(groupState))
|
|
657
|
+
: { groupMeta: undefined, accessPointMetas: undefined };
|
|
540
658
|
const handleRemoveAccessPointGroup = () => {
|
|
541
659
|
editorStore.applicationStore.alertService.setActionAlertInfo({
|
|
542
660
|
message: groupState instanceof ModelAccessPointGroupState
|
|
@@ -584,7 +702,8 @@ const AccessPointGroupEditor = observer((props) => {
|
|
|
584
702
|
overflow: 'hidden',
|
|
585
703
|
padding: '0.25rem',
|
|
586
704
|
height: 'auto',
|
|
587
|
-
} })) : (_jsxs("div", { onClick: handleDescriptionEdit, title: "Click to edit group description", className: "access-point-editor__description-container", children: [groupState.value.description ? (_jsx(HoverTextArea, { text: groupState.value.description, handleMouseOver: handleMouseOverDescription, handleMouseOut: handleMouseOutDescription, className: "access-point-editor__group-container__description" })) : (_jsxs("div", { className: "access-point-editor__group-container__description--warning", onMouseOver: handleMouseOverDescription, onMouseOut: handleMouseOutDescription, children: [_jsx(ErrorWarnIcon, {}), "Users request access at the access point group level. Click here to add a meaningful description to guide users."] })), isHoveringDescription && hoverIcon()] })), aiGroupMeta && (_jsx("div", { className: "data-product-editor__ai-suggestion-inline", children: aiGroupMeta.description }))] }),
|
|
705
|
+
} })) : (_jsxs("div", { onClick: handleDescriptionEdit, title: "Click to edit group description", className: "access-point-editor__description-container", children: [groupState.value.description ? (_jsx(HoverTextArea, { text: groupState.value.description, handleMouseOver: handleMouseOverDescription, handleMouseOut: handleMouseOutDescription, className: "access-point-editor__group-container__description" })) : (_jsxs("div", { className: "access-point-editor__group-container__description--warning", onMouseOver: handleMouseOverDescription, onMouseOut: handleMouseOutDescription, children: [_jsx(ErrorWarnIcon, {}), "Users request access at the access point group level. Click here to add a meaningful description to guide users."] })), isHoveringDescription && hoverIcon()] })), aiGroupMeta && (_jsx("div", { className: "data-product-editor__ai-suggestion-inline", children: aiGroupMeta.description }))] }), _jsxs("div", { className: "data-product-editor__operational-input data-product-editor__apg-targets-input", children: [_jsx("div", { className: "panel__content__form__section__header__label", style: { justifyContent: 'space-between', width: '45rem' }, children: "Target Environments" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "Select where this Data Product will be deployed." }), _jsx("div", { className: "panel__content__form__section__list__id-list", children: groupState.value.targets?.map((target) => (_jsxs("div", { className: "panel__content__form__section__list__item", children: [target, _jsx("button", { className: "panel__content__form__section__list__item__remove-btn", disabled: isReadOnly, onClick: () => handleRemoveTargetEnvironment(target), tabIndex: -1, title: "Remove Target Environment", children: _jsx(TimesIcon, {}) })] }, target))) }), _jsx(CustomSelectorInput, { className: "panel__content__form__section__dropdown", options: getTargetEnvironmentOptions(), onChange: handleAddTargetEnvironment, placeholder: 'Add Target Environment...', darkMode: !productEditorState.editorStore.applicationStore.layoutService
|
|
706
|
+
.TEMPORARY__isLightColorThemeEnabled, disabled: isReadOnly })] }), editorStore.applicationStore.config.options.dataProductConfig && (_jsx(AccessPointGroupPublicToggle, { groupState: groupState })), groupState instanceof ModelAccessPointGroupState ? (_jsx(ModelAccessPointGroupEditor, { groupState: groupState, isReadOnly: isReadOnly })) : (_jsxs(_Fragment, { children: [_jsxs(PanelHeader, { className: "panel__header--access-point", children: [_jsx("div", { className: "panel__header__title", children: "Access Points" }), _jsx(PanelHeaderActions, { children: _jsx(PanelHeaderActionItem, { className: "panel__header__action", onClick: handleAddAccessPoint, title: "Create new access point", children: _jsx(PlusIcon, {}) }) })] }), groupState.accessPointStates.length === 0 && (_jsxs("div", { className: "access-point-editor__group-container__description--warning", style: { color: 'var(--color-red-300)' }, children: [_jsx(WarningIcon, {}), "This group needs at least one access point defined."] })), _jsxs("div", { style: { gap: '1rem', display: 'flex', flexDirection: 'column' }, children: [lakehouseAccessPointStates
|
|
588
707
|
.slice(0, renderedCount)
|
|
589
708
|
.map((apState, idx) => (_jsx(LakehouseDataProductAccessPointEditor, { isReadOnly: isReadOnly, accessPointState: apState, aiSuggestionMeta: aiAccessPointMetas?.[idx] }, apState.uuid))), accessPointCount > renderedCount && (_jsx(AccessPointLoadingSentinel, { ref: accessPointsSentinelRef }))] })] }))] }));
|
|
590
709
|
});
|
|
@@ -899,12 +1018,12 @@ const HomeTab = observer((props) => {
|
|
|
899
1018
|
resize: 'vertical',
|
|
900
1019
|
maxHeight: '100%',
|
|
901
1020
|
maxWidth: '100%',
|
|
902
|
-
} })] }), _jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", style: { justifyContent: 'space-between', width: '45rem' }, children: "Data Product Type" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "Select if this Data Product is Internal or External" }), _jsx(
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1021
|
+
} })] }), _jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", style: { justifyContent: 'space-between', width: '45rem' }, children: "Data Product Type" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "Select if this Data Product is Internal or External" }), _jsx(CustomSelectorInput, { className: "panel__content__form__section__dropdown", options: DATA_PRODUCT_TYPE_OPTIONS, onChange: handleDataProductTypeChange, value: product.type instanceof InternalDataProductType
|
|
1022
|
+
? DATA_PRODUCT_TYPE_OPTIONS.find((option) => option.value === DATA_PRODUCT_TYPE.INTERNAL)
|
|
1023
|
+
: product.type instanceof ExternalDataProductType
|
|
1024
|
+
? DATA_PRODUCT_TYPE_OPTIONS.find((option) => option.value === DATA_PRODUCT_TYPE.EXTERNAL)
|
|
1025
|
+
: null, darkMode: !dataProductEditorState.editorStore.applicationStore
|
|
1026
|
+
.layoutService.TEMPORARY__isLightColorThemeEnabled }), product.type instanceof ExternalDataProductType && (_jsxs("div", { className: "data-product-editor__external-link", children: [_jsx("div", { className: "panel__content__form__section__header__prompt", children: "External Link" }), _jsx("textarea", { className: "input input-group__input panel__content__form__section__input input--dark input--small", spellCheck: false, disabled: isReadOnly, placeholder: "External URL", value: product.type.link.url, onChange: handleExternalURLChange, style: {
|
|
908
1027
|
resize: 'none',
|
|
909
1028
|
padding: '0.25rem 0.5rem',
|
|
910
1029
|
} }), _jsx("textarea", { className: "input input-group__input panel__content__form__section__input input--dark input--small", spellCheck: false, disabled: isReadOnly, placeholder: "External Link Label", value: product.type.link.label ?? '', onChange: handleExternalLabelChange, style: {
|
|
@@ -1099,15 +1218,15 @@ const OperationalTab = observer((props) => {
|
|
|
1099
1218
|
operationalMetadata_setUpdateFrequency(product.operationalMetadata, val.value);
|
|
1100
1219
|
}
|
|
1101
1220
|
};
|
|
1102
|
-
return (_jsxs("div", { children: [_jsx("div", { className: "panel__content__form__section__header__label", style: { paddingLeft: '1rem' }, children: "Operational Metadata" }), _jsx("div", { className: "panel__content__form__section__header__prompt", style: { paddingLeft: '1rem' }, children: "Configure operational metadata for this Data Product." }), _jsxs("div", { className: "data-product-editor__operational-input", children: [_jsx("div", { className: "panel__content__form__section__header__label", style: { justifyContent: 'space-between', width: '45rem' }, children: "Coverage Regions" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "Select the regions this Data Product covers." }), _jsx("div", { className: "panel__content__form__section__list__id-list", children: product.operationalMetadata?.coverageRegions?.map((region) => (_jsxs("div", { className: "panel__content__form__section__list__item", children: [region, _jsx("button", { className: "panel__content__form__section__list__item__remove-btn", disabled: dataProductEditorState.isReadOnly, onClick: () => handleRemoveRegion(region), tabIndex: -1, title: "Remove Region", children: _jsx(TimesIcon, {}) })] }, region))) }), _jsx(
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1221
|
+
return (_jsxs("div", { children: [_jsx("div", { className: "panel__content__form__section__header__label", style: { paddingLeft: '1rem' }, children: "Operational Metadata" }), _jsx("div", { className: "panel__content__form__section__header__prompt", style: { paddingLeft: '1rem' }, children: "Configure operational metadata for this Data Product." }), _jsxs("div", { className: "data-product-editor__operational-input", children: [_jsx("div", { className: "panel__content__form__section__header__label", style: { justifyContent: 'space-between', width: '45rem' }, children: "Coverage Regions" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "Select the regions this Data Product covers." }), _jsx("div", { className: "panel__content__form__section__list__id-list", children: product.operationalMetadata?.coverageRegions?.map((region) => (_jsxs("div", { className: "panel__content__form__section__list__item", children: [region, _jsx("button", { className: "panel__content__form__section__list__item__remove-btn", disabled: dataProductEditorState.isReadOnly, onClick: () => handleRemoveRegion(region), tabIndex: -1, title: "Remove Region", children: _jsx(TimesIcon, {}) })] }, region))) }), _jsx(CustomSelectorInput, { className: "panel__content__form__section__dropdown", options: getCoverageRegionOptions(), onChange: handleAddRegion, placeholder: CHOOSE_REGION, darkMode: true, disabled: isReadOnly })] }), _jsxs("div", { className: "data-product-editor__operational-input", children: [_jsx("div", { className: "panel__content__form__section__header__label", style: { justifyContent: 'space-between', width: '45rem' }, children: "Update Frequency" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "Select the update frequency of this Data Product." }), _jsx(CustomSelectorInput, { className: "panel__content__form__section__dropdown", options: Object.values(DeliveryFrequency).map((frequency) => ({
|
|
1222
|
+
label: frequency,
|
|
1223
|
+
value: frequency,
|
|
1224
|
+
})), onChange: handleUpdateFrequencyChange, value: product.operationalMetadata?.updateFrequency
|
|
1225
|
+
? {
|
|
1226
|
+
label: product.operationalMetadata.updateFrequency,
|
|
1227
|
+
value: product.operationalMetadata.updateFrequency,
|
|
1228
|
+
}
|
|
1229
|
+
: null, placeholder: "Select update frequency...", darkMode: true, disabled: isReadOnly })] })] }));
|
|
1111
1230
|
});
|
|
1112
1231
|
export const DataProductEditor = observer(() => {
|
|
1113
1232
|
const editorStore = useEditorStore();
|