@finos/legend-application-studio 28.21.17 → 28.21.19

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 (24) hide show
  1. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.d.ts.map +1 -1
  2. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js +5 -3
  3. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js.map +1 -1
  4. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.d.ts.map +1 -1
  5. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js +1 -19
  6. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js.map +1 -1
  7. package/lib/components/editor/editor-group/uml-editor/StereotypeSelector.d.ts.map +1 -1
  8. package/lib/components/editor/editor-group/uml-editor/StereotypeSelector.js +7 -2
  9. package/lib/components/editor/editor-group/uml-editor/StereotypeSelector.js.map +1 -1
  10. package/lib/components/editor/editor-group/uml-editor/TaggedValueEditor.d.ts.map +1 -1
  11. package/lib/components/editor/editor-group/uml-editor/TaggedValueEditor.js +9 -4
  12. package/lib/components/editor/editor-group/uml-editor/TaggedValueEditor.js.map +1 -1
  13. package/lib/index.css +1 -1
  14. package/lib/package.json +1 -1
  15. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts +2 -4
  16. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts.map +1 -1
  17. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +98 -64
  18. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
  19. package/package.json +14 -14
  20. package/src/components/editor/editor-group/data-editor/RelationElementsDataEditor.tsx +5 -3
  21. package/src/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.tsx +3 -32
  22. package/src/components/editor/editor-group/uml-editor/StereotypeSelector.tsx +9 -3
  23. package/src/components/editor/editor-group/uml-editor/TaggedValueEditor.tsx +11 -5
  24. package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +145 -85
@@ -14,7 +14,14 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { action, flow, flowResult, makeObservable, observable } from 'mobx';
17
+ import {
18
+ action,
19
+ flow,
20
+ flowResult,
21
+ makeObservable,
22
+ observable,
23
+ runInAction,
24
+ } from 'mobx';
18
25
  import type { EditorStore } from '../../../../EditorStore.js';
19
26
  import type { FunctionEditorState } from '../../FunctionEditorState.js';
20
27
  import {
@@ -43,6 +50,8 @@ import {
43
50
  type ValueSpecification,
44
51
  type TestAssertion,
45
52
  type AccessorOwner,
53
+ type AbstractPureGraphManager,
54
+ type PackageableElement,
46
55
  FunctionParameterValue,
47
56
  VariableExpression,
48
57
  FunctionTest,
@@ -57,8 +66,11 @@ import {
57
66
  InstanceValue,
58
67
  PackageableElementReference,
59
68
  Database,
69
+ DataProduct,
70
+ IngestDefinition,
60
71
  PackageableElementExplicitReference,
61
72
  observe_ValueSpecification,
73
+ observe_RelationElementsData,
62
74
  buildLambdaVariableExpressions,
63
75
  EqualTo,
64
76
  EqualToRelation,
@@ -72,7 +84,7 @@ import {
72
84
  type Accessor,
73
85
  DataProductAccessor,
74
86
  IngestionAccessor,
75
- RelationalStoreAccessor,
87
+ getAccessorItemLabelForElement,
76
88
  V1_buildRelationElementsDataFromAccessors,
77
89
  } from '@finos/legend-graph';
78
90
  import {
@@ -191,6 +203,28 @@ const resolveRuntimesFromQuery = (
191
203
  }
192
204
  };
193
205
 
206
+ interface ElementDataItem {
207
+ id: string;
208
+ label: string;
209
+ }
210
+
211
+ const getElementDataItems = (
212
+ element: PackageableElement,
213
+ graphManager: AbstractPureGraphManager,
214
+ ): ElementDataItem[] => {
215
+ if (element instanceof DataProduct) {
216
+ return element.accessPointGroups
217
+ .flatMap((g) => g.accessPoints)
218
+ .map((ap) => ({ id: ap.id, label: ap.id }));
219
+ }
220
+ if (element instanceof IngestDefinition) {
221
+ return graphManager
222
+ .getIngestDefinitionDatasetNames(element)
223
+ .map((name) => ({ id: name, label: name }));
224
+ }
225
+ return [];
226
+ };
227
+
194
228
  export class FunctionStoreTestDataState {
195
229
  readonly editorStore: EditorStore;
196
230
  readonly testDataState: FunctionTestDataState;
@@ -239,51 +273,69 @@ export class FunctionStoreTestDataState {
239
273
  embeddedDataState: RelationElementsDataState,
240
274
  ): Promise<void> {
241
275
  const parentElement = this.storeTestData.element.value;
242
- const accessors =
243
- this.testDataState.functionTestableState
244
- .resolvedIngestOrDataProductAccessors;
245
- const parentAccessors = accessors.filter(
246
- (a) => a.accessorOwner === parentElement.path,
247
- );
248
- if (!parentAccessors.length) {
276
+ const graphManager = this.editorStore.graphManagerState.graphManager;
277
+ const graph = this.editorStore.graphManagerState.graph;
278
+
279
+ // For Database parents, fall back to the schema+table form
280
+ if (parentElement instanceof Database) {
249
281
  embeddedDataState.setAccessorOptions(undefined, undefined);
250
282
  return;
251
283
  }
252
- const firstAccessor = parentAccessors[0];
253
- if (!firstAccessor) {
284
+
285
+ const items = getElementDataItems(parentElement, graphManager);
286
+ if (items.length === 0) {
254
287
  embeddedDataState.setAccessorOptions(undefined, undefined);
255
288
  return;
256
289
  }
257
-
258
- const columnOverrides = new Map<string, string[]>();
259
- for (const accessor of parentAccessors) {
260
- const cols = accessor.relationType.columns.map((col) => col.name);
261
- if (cols.length > 0) {
262
- columnOverrides.set(accessor.accessor, cols);
263
- }
264
- }
265
-
266
- const typeLabel = firstAccessor.accessorLabel;
267
- const options = parentAccessors.map((a) => ({
268
- label: a.accessor,
269
- value: a.accessor,
270
- columns: columnOverrides.get(a.accessor) ?? [],
271
- }));
272
-
273
- if (columnOverrides.size > 0) {
290
+ const typeLabel = getAccessorItemLabelForElement(
291
+ parentElement as AccessorOwner,
292
+ );
293
+ const options = await Promise.all(
294
+ items.map(async (item) => {
295
+ let columns: string[] = [];
296
+ try {
297
+ if (parentElement instanceof IngestDefinition) {
298
+ const accessor =
299
+ await graphManager.createAccessorFromPackageableElement(
300
+ parentElement,
301
+ graph,
302
+ { schemaName: undefined, tableName: item.id },
303
+ );
304
+ if (accessor) {
305
+ columns = accessor.relationType.columns.map((c) => c.name);
306
+ }
307
+ } else if (parentElement instanceof DataProduct) {
308
+ const accessor = await graphManager.buildDataProductAccessor(
309
+ parentElement,
310
+ graph,
311
+ { tableName: item.id },
312
+ );
313
+ if (accessor) {
314
+ columns = accessor.relationType.columns.map((c) => c.name);
315
+ }
316
+ }
317
+ } catch {}
318
+ return { label: item.label, value: item.id, columns };
319
+ }),
320
+ );
321
+ runInAction(() => {
322
+ embeddedDataState.setAccessorOptions(options, typeLabel);
323
+ const columnsByItem = new Map(
324
+ options
325
+ .filter((o) => o.columns.length > 0)
326
+ .map((o) => [o.value, o.columns]),
327
+ );
274
328
  for (const relState of embeddedDataState.relationElementStates) {
275
329
  const rel = relState.relationElement;
276
330
  if (rel.columns.length === 0) {
277
331
  const key = rel.paths[rel.paths.length - 1];
278
- const cols = key ? columnOverrides.get(key) : undefined;
332
+ const cols = key ? columnsByItem.get(key) : undefined;
279
333
  if (cols) {
280
334
  rel.columns = cols;
281
335
  }
282
336
  }
283
337
  }
284
- }
285
-
286
- embeddedDataState.setAccessorOptions(options, typeLabel);
338
+ });
287
339
  }
288
340
 
289
341
  setDataElementModal(val: boolean): void {
@@ -655,34 +707,38 @@ class FunctionTestDataState {
655
707
  return (this.dataHolder.testData ?? []).map((td) => td.element.value.path);
656
708
  }
657
709
 
658
- get availableElementsToAdd(): { path: string }[] {
659
- const accessors =
660
- this.functionTestableState.resolvedIngestOrDataProductAccessors;
710
+ get availableElementsToAdd(): PackageableElement[] {
711
+ const graph = this.editorStore.graphManagerState.graph;
661
712
  const existingPaths = new Set(this.existingElementPaths);
662
- const parentPaths = new Set<string>();
663
- for (const accessor of accessors) {
664
- const parentPath = accessor.path[0];
665
- if (parentPath && !existingPaths.has(parentPath)) {
666
- parentPaths.add(parentPath);
667
- }
668
- }
669
- return Array.from(parentPaths).map((path) => ({ path }));
713
+ const candidates: PackageableElement[] = [
714
+ ...graph.ingests,
715
+ ...graph.dataProducts,
716
+ ...graph.databases,
717
+ ];
718
+ return candidates.filter((e) => !existingPaths.has(e.path));
670
719
  }
671
720
 
672
721
  addDataElement(elementPath: string): void {
673
- const accessors =
674
- this.functionTestableState.resolvedIngestOrDataProductAccessors;
675
- const group = accessors.filter((a) => a.path[0] === elementPath);
676
- if (!group.length) {
722
+ const element =
723
+ this.editorStore.graphManagerState.graph.getNullableElement(elementPath);
724
+ if (!element) {
677
725
  return;
678
726
  }
679
- const element =
680
- this.editorStore.graphManagerState.graph.getElement(elementPath);
681
727
  const data = new FunctionTestData();
682
728
  data.element = PackageableElementExplicitReference.create(
683
729
  element as AccessorOwner,
684
730
  );
685
- data.data = V1_buildRelationElementsDataFromAccessors(group);
731
+ const matchingAccessors = this.functionTestableState.cachedAccessors.filter(
732
+ (a) => a.accessorOwner === elementPath,
733
+ );
734
+ if (matchingAccessors.length) {
735
+ data.data = V1_buildRelationElementsDataFromAccessors(matchingAccessors);
736
+ } else {
737
+ const relData = new RelationElementsData();
738
+ relData.relationElements = [];
739
+ data.data = relData;
740
+ }
741
+ observe_RelationElementsData(data.data as RelationElementsData);
686
742
  if (!this.dataHolder.testData) {
687
743
  this.dataHolder.testData = [];
688
744
  }
@@ -966,36 +1022,9 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
966
1022
 
967
1023
  const ingestOrDataProductAccessors =
968
1024
  this.resolvedIngestOrDataProductAccessors;
969
- const databaseAccessors = this.cachedAccessors.filter(
970
- (a) => a instanceof RelationalStoreAccessor,
971
- );
972
1025
 
973
1026
  try {
974
- if (ingestOrDataProductAccessors.length) {
975
- // Group by parent element path and create test data per parent
976
- const parentElementMap = new Map<string, Accessor[]>();
977
- for (const accessor of ingestOrDataProductAccessors) {
978
- const key = accessor.accessorOwner;
979
- if (key) {
980
- const group = parentElementMap.get(key) ?? [];
981
- group.push(accessor);
982
- parentElementMap.set(key, group);
983
- }
984
- }
985
- functionSuite.testData = Array.from(parentElementMap.entries()).map(
986
- ([parentPath, group]) => {
987
- const data = new FunctionTestData();
988
- const element =
989
- this.editorStore.graphManagerState.graph.getElement(parentPath);
990
- data.element = PackageableElementExplicitReference.create(
991
- element as AccessorOwner,
992
- );
993
- data.data = V1_buildRelationElementsDataFromAccessors(group);
994
- return data;
995
- },
996
- );
997
- } else {
998
- // No ingest/data product accessors found — try runtime-based approach
1027
+ if (!ingestOrDataProductAccessors.length) {
999
1028
  const engineRuntimes = this.associatedRuntimes;
1000
1029
  if (engineRuntimes?.length) {
1001
1030
  assertTrue(
@@ -1047,10 +1076,44 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
1047
1076
  type.path === CORE_PURE_PATH.RELATION ||
1048
1077
  type.path === CORE_PURE_PATH.TABULAR_DATASET
1049
1078
  ) {
1050
- this.editorStore.applicationStore.notificationService.notifyError(
1051
- `Unable to create function test suite: no runtime or accessors found, or they could not be resolved`,
1079
+ this.editorStore.applicationStore.notificationService.notifyWarning(
1080
+ `No runtime or accessors found, or they could not be resolved. For Relational (non-Lakehouse) function testing, please ensure that your query is bound to a runtime`,
1081
+ );
1082
+ // continue: still allow the user to create the suite/test and
1083
+ // add test data manually
1084
+ }
1085
+ }
1086
+ }
1087
+
1088
+ if (this.cachedAccessors.length) {
1089
+ const accessorsByOwner = new Map<string, Accessor[]>();
1090
+ for (const accessor of this.cachedAccessors) {
1091
+ const key = accessor.accessorOwner;
1092
+ if (key) {
1093
+ const group = accessorsByOwner.get(key) ?? [];
1094
+ group.push(accessor);
1095
+ accessorsByOwner.set(key, group);
1096
+ }
1097
+ }
1098
+ if (!functionSuite.testData) {
1099
+ functionSuite.testData = [];
1100
+ }
1101
+ for (const [parentPath, group] of accessorsByOwner.entries()) {
1102
+ const builtData = V1_buildRelationElementsDataFromAccessors(group);
1103
+ const existing = functionSuite.testData.find(
1104
+ (td) => td.element.value.path === parentPath,
1105
+ );
1106
+ if (existing) {
1107
+ existing.data = builtData;
1108
+ } else {
1109
+ const element =
1110
+ this.editorStore.graphManagerState.graph.getElement(parentPath);
1111
+ const data = new FunctionTestData();
1112
+ data.element = PackageableElementExplicitReference.create(
1113
+ element as AccessorOwner,
1052
1114
  );
1053
- return;
1115
+ data.data = builtData;
1116
+ functionSuite.testData.push(data);
1054
1117
  }
1055
1118
  }
1056
1119
  }
@@ -1062,10 +1125,7 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
1062
1125
  return;
1063
1126
  }
1064
1127
 
1065
- const hasTestData =
1066
- this.containsRuntime ||
1067
- ingestOrDataProductAccessors.length > 0 ||
1068
- databaseAccessors.length > 0;
1128
+ const hasTestData = this.containsRuntime || this.cachedAccessors.length > 0;
1069
1129
  yield createFunctionTest(
1070
1130
  testName,
1071
1131
  this.editorStore.changeDetectionState.observerContext,