@finos/legend-application-studio 28.21.45 → 28.21.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/lib/__lib__/LegendStudioEvent.d.ts +63 -1
  2. package/lib/__lib__/LegendStudioEvent.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioEvent.js +90 -0
  4. package/lib/__lib__/LegendStudioEvent.js.map +1 -1
  5. package/lib/__lib__/LegendStudioTelemetryHelper.d.ts +655 -1
  6. package/lib/__lib__/LegendStudioTelemetryHelper.d.ts.map +1 -1
  7. package/lib/__lib__/LegendStudioTelemetryHelper.js +709 -1
  8. package/lib/__lib__/LegendStudioTelemetryHelper.js.map +1 -1
  9. package/lib/components/editor/editor-group/LegendAISuggestTelemetryHooks.d.ts +30 -0
  10. package/lib/components/editor/editor-group/LegendAISuggestTelemetryHooks.d.ts.map +1 -0
  11. package/lib/components/editor/editor-group/LegendAISuggestTelemetryHooks.js +43 -0
  12. package/lib/components/editor/editor-group/LegendAISuggestTelemetryHooks.js.map +1 -0
  13. package/lib/components/editor/editor-group/RuntimeEditor.d.ts +4 -3
  14. package/lib/components/editor/editor-group/RuntimeEditor.d.ts.map +1 -1
  15. package/lib/components/editor/editor-group/RuntimeEditor.js +90 -36
  16. package/lib/components/editor/editor-group/RuntimeEditor.js.map +1 -1
  17. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts.map +1 -1
  18. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js +154 -35
  19. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
  20. package/lib/components/editor/editor-group/dataProduct/DataProductQueryBuilderHelper.d.ts.map +1 -1
  21. package/lib/components/editor/editor-group/dataProduct/DataProductQueryBuilderHelper.js +4 -6
  22. package/lib/components/editor/editor-group/dataProduct/DataProductQueryBuilderHelper.js.map +1 -1
  23. package/lib/components/editor/editor-group/service-editor/ServiceEditor.d.ts.map +1 -1
  24. package/lib/components/editor/editor-group/service-editor/ServiceEditor.js +31 -7
  25. package/lib/components/editor/editor-group/service-editor/ServiceEditor.js.map +1 -1
  26. package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.d.ts.map +1 -1
  27. package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.js +4 -8
  28. package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.js.map +1 -1
  29. package/lib/components/editor/side-bar/WorkflowManager.d.ts.map +1 -1
  30. package/lib/components/editor/side-bar/WorkflowManager.js +15 -0
  31. package/lib/components/editor/side-bar/WorkflowManager.js.map +1 -1
  32. package/lib/index.css +1 -1
  33. package/lib/index.d.ts +3 -1
  34. package/lib/index.d.ts.map +1 -1
  35. package/lib/index.js +3 -1
  36. package/lib/index.js.map +1 -1
  37. package/lib/package.json +1 -1
  38. package/lib/stores/editor/EditorGraphState.d.ts.map +1 -1
  39. package/lib/stores/editor/EditorGraphState.js +17 -1
  40. package/lib/stores/editor/EditorGraphState.js.map +1 -1
  41. package/lib/stores/editor/EditorStore.d.ts +2 -0
  42. package/lib/stores/editor/EditorStore.d.ts.map +1 -1
  43. package/lib/stores/editor/EditorStore.js +12 -0
  44. package/lib/stores/editor/EditorStore.js.map +1 -1
  45. package/lib/stores/editor/EditorTabManagerState.d.ts +18 -1
  46. package/lib/stores/editor/EditorTabManagerState.d.ts.map +1 -1
  47. package/lib/stores/editor/EditorTabManagerState.js +90 -1
  48. package/lib/stores/editor/EditorTabManagerState.js.map +1 -1
  49. package/lib/stores/editor/EditorTabTelemetryHelper.d.ts +31 -0
  50. package/lib/stores/editor/EditorTabTelemetryHelper.d.ts.map +1 -0
  51. package/lib/stores/editor/EditorTabTelemetryHelper.js +55 -0
  52. package/lib/stores/editor/EditorTabTelemetryHelper.js.map +1 -0
  53. package/lib/stores/editor/GraphEditFormModeState.d.ts.map +1 -1
  54. package/lib/stores/editor/GraphEditFormModeState.js +22 -1
  55. package/lib/stores/editor/GraphEditFormModeState.js.map +1 -1
  56. package/lib/stores/editor/LegendAISuggestTelemetry.d.ts +143 -0
  57. package/lib/stores/editor/LegendAISuggestTelemetry.d.ts.map +1 -0
  58. package/lib/stores/editor/LegendAISuggestTelemetry.js +376 -0
  59. package/lib/stores/editor/LegendAISuggestTelemetry.js.map +1 -0
  60. package/lib/stores/editor/LegendSQLStudioPlaygroundState.js +3 -3
  61. package/lib/stores/editor/LegendSQLStudioPlaygroundState.js.map +1 -1
  62. package/lib/stores/editor/editor-state/GraphGenerationState.d.ts +14 -3
  63. package/lib/stores/editor/editor-state/GraphGenerationState.d.ts.map +1 -1
  64. package/lib/stores/editor/editor-state/GraphGenerationState.js +42 -5
  65. package/lib/stores/editor/editor-state/GraphGenerationState.js.map +1 -1
  66. package/lib/stores/editor/editor-state/ModelImporterState.d.ts.map +1 -1
  67. package/lib/stores/editor/editor-state/ModelImporterState.js +2 -1
  68. package/lib/stores/editor/editor-state/ModelImporterState.js.map +1 -1
  69. package/lib/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.d.ts.map +1 -1
  70. package/lib/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.js +14 -0
  71. package/lib/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.js.map +1 -1
  72. package/lib/stores/editor/editor-state/element-editor-state/RuntimeEditorState.d.ts +35 -6
  73. package/lib/stores/editor/editor-state/element-editor-state/RuntimeEditorState.d.ts.map +1 -1
  74. package/lib/stores/editor/editor-state/element-editor-state/RuntimeEditorState.js +74 -29
  75. package/lib/stores/editor/editor-state/element-editor-state/RuntimeEditorState.js.map +1 -1
  76. package/lib/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.d.ts +5 -0
  77. package/lib/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.d.ts.map +1 -1
  78. package/lib/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.js +13 -0
  79. package/lib/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.js.map +1 -1
  80. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts +1 -0
  81. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts.map +1 -1
  82. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js +5 -5
  83. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js.map +1 -1
  84. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +12 -0
  85. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts.map +1 -1
  86. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js +60 -14
  87. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
  88. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts +5 -0
  89. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts.map +1 -1
  90. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js +13 -0
  91. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js.map +1 -1
  92. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts +7 -0
  93. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts.map +1 -1
  94. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +21 -2
  95. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
  96. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.d.ts +5 -0
  97. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.d.ts.map +1 -1
  98. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.js +13 -0
  99. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.js.map +1 -1
  100. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts +7 -0
  101. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts.map +1 -1
  102. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js +34 -0
  103. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js.map +1 -1
  104. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts.map +1 -1
  105. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js +48 -0
  106. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js.map +1 -1
  107. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts +1 -1
  108. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts.map +1 -1
  109. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js +5 -11
  110. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js.map +1 -1
  111. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts +3 -0
  112. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts.map +1 -1
  113. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js +7 -0
  114. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js.map +1 -1
  115. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestableState.d.ts.map +1 -1
  116. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestableState.js +46 -17
  117. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestableState.js.map +1 -1
  118. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.d.ts +7 -0
  119. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.d.ts.map +1 -1
  120. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.js +110 -16
  121. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.js.map +1 -1
  122. package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.d.ts +2 -1
  123. package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.d.ts.map +1 -1
  124. package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js +10 -4
  125. package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js.map +1 -1
  126. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.d.ts.map +1 -1
  127. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.js +40 -1
  128. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.js.map +1 -1
  129. package/lib/stores/editor/sidebar-state/LocalChangesState.d.ts.map +1 -1
  130. package/lib/stores/editor/sidebar-state/LocalChangesState.js +1 -0
  131. package/lib/stores/editor/sidebar-state/LocalChangesState.js.map +1 -1
  132. package/lib/stores/editor/sidebar-state/ProjectOverviewState.d.ts.map +1 -1
  133. package/lib/stores/editor/sidebar-state/ProjectOverviewState.js +51 -0
  134. package/lib/stores/editor/sidebar-state/ProjectOverviewState.js.map +1 -1
  135. package/lib/stores/editor/sidebar-state/WorkflowManagerState.d.ts +14 -0
  136. package/lib/stores/editor/sidebar-state/WorkflowManagerState.d.ts.map +1 -1
  137. package/lib/stores/editor/sidebar-state/WorkflowManagerState.js +132 -27
  138. package/lib/stores/editor/sidebar-state/WorkflowManagerState.js.map +1 -1
  139. package/lib/stores/editor/sidebar-state/WorkspaceReviewState.d.ts.map +1 -1
  140. package/lib/stores/editor/sidebar-state/WorkspaceReviewState.js +41 -0
  141. package/lib/stores/editor/sidebar-state/WorkspaceReviewState.js.map +1 -1
  142. package/lib/stores/editor/sidebar-state/testable/GlobalTestRunnerState.d.ts.map +1 -1
  143. package/lib/stores/editor/sidebar-state/testable/GlobalTestRunnerState.js +71 -9
  144. package/lib/stores/editor/sidebar-state/testable/GlobalTestRunnerState.js.map +1 -1
  145. package/lib/stores/editor/utils/MockDataUtils.d.ts +12 -2
  146. package/lib/stores/editor/utils/MockDataUtils.d.ts.map +1 -1
  147. package/lib/stores/editor/utils/MockDataUtils.js +28 -28
  148. package/lib/stores/editor/utils/MockDataUtils.js.map +1 -1
  149. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts +2 -0
  150. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
  151. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js +13 -0
  152. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js.map +1 -1
  153. package/lib/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.d.ts +20 -2
  154. package/lib/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.d.ts.map +1 -1
  155. package/lib/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.js +38 -4
  156. package/lib/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.js.map +1 -1
  157. package/lib/stores/project-reviewer/ProjectReviewerStore.d.ts.map +1 -1
  158. package/lib/stores/project-reviewer/ProjectReviewerStore.js +45 -0
  159. package/lib/stores/project-reviewer/ProjectReviewerStore.js.map +1 -1
  160. package/lib/stores/workspace-setup/WorkspaceSetupStore.d.ts.map +1 -1
  161. package/lib/stores/workspace-setup/WorkspaceSetupStore.js +48 -4
  162. package/lib/stores/workspace-setup/WorkspaceSetupStore.js.map +1 -1
  163. package/package.json +9 -9
  164. package/src/__lib__/LegendStudioEvent.ts +102 -0
  165. package/src/__lib__/LegendStudioTelemetryHelper.ts +1769 -311
  166. package/src/components/editor/editor-group/LegendAISuggestTelemetryHooks.ts +57 -0
  167. package/src/components/editor/editor-group/RuntimeEditor.tsx +282 -132
  168. package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +293 -106
  169. package/src/components/editor/editor-group/dataProduct/DataProductQueryBuilderHelper.ts +3 -13
  170. package/src/components/editor/editor-group/service-editor/ServiceEditor.tsx +41 -23
  171. package/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx +5 -11
  172. package/src/components/editor/side-bar/WorkflowManager.tsx +24 -0
  173. package/src/index.ts +17 -1
  174. package/src/stores/editor/EditorGraphState.ts +30 -1
  175. package/src/stores/editor/EditorStore.ts +22 -0
  176. package/src/stores/editor/EditorTabManagerState.ts +128 -1
  177. package/src/stores/editor/EditorTabTelemetryHelper.ts +70 -0
  178. package/src/stores/editor/GraphEditFormModeState.ts +35 -1
  179. package/src/stores/editor/LegendAISuggestTelemetry.ts +592 -0
  180. package/src/stores/editor/LegendSQLStudioPlaygroundState.ts +3 -3
  181. package/src/stores/editor/editor-state/GraphGenerationState.ts +68 -9
  182. package/src/stores/editor/editor-state/ModelImporterState.ts +2 -0
  183. package/src/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.ts +30 -0
  184. package/src/stores/editor/editor-state/element-editor-state/RuntimeEditorState.ts +92 -31
  185. package/src/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.ts +17 -0
  186. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +6 -6
  187. package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +75 -17
  188. package/src/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.ts +17 -0
  189. package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +27 -2
  190. package/src/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.ts +17 -0
  191. package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.ts +57 -0
  192. package/src/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.ts +74 -0
  193. package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts +22 -21
  194. package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.ts +9 -0
  195. package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestableState.ts +78 -21
  196. package/src/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.ts +205 -18
  197. package/src/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.ts +38 -3
  198. package/src/stores/editor/sidebar-state/BulkServiceRegistrationState.ts +71 -1
  199. package/src/stores/editor/sidebar-state/LocalChangesState.ts +4 -0
  200. package/src/stores/editor/sidebar-state/ProjectOverviewState.ts +114 -0
  201. package/src/stores/editor/sidebar-state/WorkflowManagerState.ts +250 -29
  202. package/src/stores/editor/sidebar-state/WorkspaceReviewState.ts +84 -0
  203. package/src/stores/editor/sidebar-state/testable/GlobalTestRunnerState.ts +124 -17
  204. package/src/stores/editor/utils/MockDataUtils.ts +33 -32
  205. package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +18 -0
  206. package/src/stores/graph-modifier/DSL_LakehouseRuntime_GraphModifierHelper.ts +62 -7
  207. package/src/stores/project-reviewer/ProjectReviewerStore.ts +97 -0
  208. package/src/stores/workspace-setup/WorkspaceSetupStore.ts +87 -4
  209. package/tsconfig.json +3 -0
@@ -117,7 +117,8 @@ import {
117
117
  type LakehouseAccessPoint,
118
118
  type Mapping,
119
119
  type PackageableElement,
120
- type DataProduct,
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 { LegendStudioTelemetryHelper } from '../../../../__lib__/LegendStudioTelemetryHelper.js';
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
- LegendStudioTelemetryHelper.logEvent_DataProductLegendAISuggestLaunched(
1295
- editorStore.applicationStore.telemetryService,
1296
- productEditorState.product.path,
1297
- editorStore.editorMode.getSourceInfo(),
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
- LegendStudioTelemetryHelper.logEvent_DataProductLegendAISuggestFailure(
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
- LegendStudioTelemetryHelper.logEvent_DataProductLegendAISuggestApplied(
1347
- editorStore.applicationStore.telemetryService,
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 gIdx =
1353
- productEditorState.accessPointGroupStates.indexOf(groupState);
1354
- const groupMeta =
1355
- aiSuggestion.access_point_groups.find(
1356
- (g) => g.name === groupState.value.id,
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 apMetas = aiSuggestion.access_points.filter(
1367
- (ap) => ap.group === (groupMeta?.name ?? groupState.value.id),
1484
+ const accessPointsUpdated = Math.min(
1485
+ apMetas.length,
1486
+ group.accessPoints.length,
1368
1487
  );
1369
- for (
1370
- let j = 0;
1371
- j < apMetas.length && j < groupState.value.accessPoints.length;
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 = groupState.value.accessPoints[
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
- LegendStudioTelemetryHelper.logEvent_DataProductLegendAISuggestDiscarded(
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 groupIndex =
1399
- productEditorState.accessPointGroupStates.indexOf(groupState);
1400
- const aiGroupMeta =
1401
- aiSuggestion?.access_point_groups.find(
1402
- (g) => g.name === groupState.value.id,
1403
- ) ?? aiSuggestion?.access_point_groups[groupIndex];
1404
- const aiAccessPointMetas = aiSuggestion?.access_points.filter(
1405
- (ap) => ap.group === (aiGroupMeta?.name ?? groupState.value.id),
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
- <div className="panel__content__form__section__list__new-item__input">
2379
- <CustomSelectorInput
2380
- options={DATA_PRODUCT_TYPE_OPTIONS}
2381
- onChange={handleDataProductTypeChange}
2382
- value={
2383
- product.type instanceof InternalDataProductType
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.INTERNAL,
2580
+ (option) => option.value === DATA_PRODUCT_TYPE.EXTERNAL,
2386
2581
  )
2387
- : product.type instanceof ExternalDataProductType
2388
- ? DATA_PRODUCT_TYPE_OPTIONS.find(
2389
- (option) =>
2390
- option.value === DATA_PRODUCT_TYPE.EXTERNAL,
2391
- )
2392
- : null
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
- <div className="panel__content__form__section__list__new-item__input">
2998
- <CustomSelectorInput<EnumOption<Region>>
2999
- options={getCoverageRegionOptions()}
3000
- onChange={handleAddRegion}
3001
- placeholder={CHOOSE_REGION}
3002
- darkMode={true}
3003
- disabled={isReadOnly}
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
- <div className="panel__content__form__section__list__new-item__input">
3018
- <CustomSelectorInput<EnumOption<DeliveryFrequency>>
3019
- options={(
3020
- Object.values(DeliveryFrequency) as DeliveryFrequency[]
3021
- ).map((frequency) => ({
3022
- label: frequency,
3023
- value: frequency,
3024
- }))}
3025
- onChange={handleUpdateFrequencyChange}
3026
- value={
3027
- product.operationalMetadata?.updateFrequency
3028
- ? {
3029
- label: product.operationalMetadata.updateFrequency,
3030
- value: product.operationalMetadata.updateFrequency,
3031
- }
3032
- : null
3033
- }
3034
- placeholder="Select update frequency..."
3035
- darkMode={true}
3036
- disabled={isReadOnly}
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 ?? nativeAccessPoints;
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, model or native access point',
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(