@finos/legend-application-studio 28.21.4 → 28.21.6
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 +4 -1
- package/lib/__lib__/LegendStudioEvent.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioEvent.js +3 -0
- package/lib/__lib__/LegendStudioEvent.js.map +1 -1
- package/lib/__lib__/LegendStudioTelemetryHelper.d.ts +2 -1
- package/lib/__lib__/LegendStudioTelemetryHelper.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioTelemetryHelper.js +11 -3
- package/lib/__lib__/LegendStudioTelemetryHelper.js.map +1 -1
- package/lib/__lib__/LegendStudioUserDataHelper.d.ts +41 -1
- package/lib/__lib__/LegendStudioUserDataHelper.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioUserDataHelper.js +120 -1
- package/lib/__lib__/LegendStudioUserDataHelper.js.map +1 -1
- package/lib/components/editor/editor-group/data-editor/EmbeddedDataEditor.d.ts +1 -1
- package/lib/components/editor/editor-group/data-editor/EmbeddedDataEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/data-editor/EmbeddedDataEditor.js +3 -3
- package/lib/components/editor/editor-group/data-editor/EmbeddedDataEditor.js.map +1 -1
- package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.d.ts +3 -0
- package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js +13 -35
- package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.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 +20 -7
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.js +59 -22
- package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.js.map +1 -1
- package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js +113 -75
- package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js.map +1 -1
- package/lib/components/editor/editor-group/testable/TestableSharedComponents.d.ts.map +1 -1
- package/lib/components/editor/editor-group/testable/TestableSharedComponents.js +2 -2
- package/lib/components/editor/editor-group/testable/TestableSharedComponents.js.map +1 -1
- package/lib/components/editor/side-bar/DevMetadataPanel.d.ts.map +1 -1
- package/lib/components/editor/side-bar/DevMetadataPanel.js +37 -6
- package/lib/components/editor/side-bar/DevMetadataPanel.js.map +1 -1
- package/lib/components/workspace-setup/RecentWorkspacesPanel.d.ts +22 -0
- package/lib/components/workspace-setup/RecentWorkspacesPanel.d.ts.map +1 -0
- package/lib/components/workspace-setup/RecentWorkspacesPanel.js +80 -0
- package/lib/components/workspace-setup/RecentWorkspacesPanel.js.map +1 -0
- package/lib/components/workspace-setup/WorkspaceSetup.d.ts.map +1 -1
- package/lib/components/workspace-setup/WorkspaceSetup.js +61 -6
- package/lib/components/workspace-setup/WorkspaceSetup.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/EditorStore.d.ts.map +1 -1
- package/lib/stores/editor/EditorStore.js +31 -0
- package/lib/stores/editor/EditorStore.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.d.ts +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.js +20 -48
- package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts +9 -14
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js +125 -78
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts +18 -4
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +216 -53
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/ProjectOverviewState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/ProjectOverviewState.js +11 -0
- package/lib/stores/editor/sidebar-state/ProjectOverviewState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/WorkspaceReviewState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/WorkspaceReviewState.js +11 -0
- package/lib/stores/editor/sidebar-state/WorkspaceReviewState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.d.ts +9 -0
- package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.js +57 -1
- package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.js.map +1 -1
- package/lib/stores/project-reviewer/ProjectReviewerStore.d.ts.map +1 -1
- package/lib/stores/project-reviewer/ProjectReviewerStore.js +12 -0
- package/lib/stores/project-reviewer/ProjectReviewerStore.js.map +1 -1
- package/lib/stores/workspace-setup/WorkspaceSetupStore.d.ts +17 -0
- package/lib/stores/workspace-setup/WorkspaceSetupStore.d.ts.map +1 -1
- package/lib/stores/workspace-setup/WorkspaceSetupStore.js +61 -0
- package/lib/stores/workspace-setup/WorkspaceSetupStore.js.map +1 -1
- package/package.json +16 -16
- package/src/__lib__/LegendStudioEvent.ts +3 -0
- package/src/__lib__/LegendStudioTelemetryHelper.ts +35 -11
- package/src/__lib__/LegendStudioUserDataHelper.ts +204 -1
- package/src/components/editor/editor-group/data-editor/EmbeddedDataEditor.tsx +4 -0
- package/src/components/editor/editor-group/data-editor/RelationElementsDataEditor.tsx +209 -187
- package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +26 -7
- package/src/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.tsx +149 -86
- package/src/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.tsx +425 -308
- package/src/components/editor/editor-group/testable/TestableSharedComponents.tsx +3 -11
- package/src/components/editor/side-bar/DevMetadataPanel.tsx +194 -10
- package/src/components/workspace-setup/RecentWorkspacesPanel.tsx +161 -0
- package/src/components/workspace-setup/WorkspaceSetup.tsx +97 -8
- package/src/stores/editor/EditorStore.ts +44 -0
- package/src/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.ts +28 -50
- package/src/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.ts +164 -100
- package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +307 -72
- package/src/stores/editor/sidebar-state/ProjectOverviewState.ts +14 -0
- package/src/stores/editor/sidebar-state/WorkspaceReviewState.ts +14 -0
- package/src/stores/editor/sidebar-state/dev-metadata/DevMetadataState.ts +84 -1
- package/src/stores/project-reviewer/ProjectReviewerStore.ts +15 -0
- package/src/stores/workspace-setup/WorkspaceSetupStore.ts +93 -0
- package/tsconfig.json +1 -0
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { action, flow, makeObservable, observable } from 'mobx';
|
|
17
|
+
import { action, flow, flowResult, makeObservable, observable } from 'mobx';
|
|
18
18
|
import type { EditorStore } from '../../../../EditorStore.js';
|
|
19
19
|
import type { FunctionEditorState } from '../../FunctionEditorState.js';
|
|
20
20
|
import {
|
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
filterByType,
|
|
32
32
|
deleteEntry,
|
|
33
33
|
UnsupportedOperationError,
|
|
34
|
+
noop,
|
|
35
|
+
type GeneratorFn,
|
|
34
36
|
} from '@finos/legend-shared';
|
|
35
37
|
import {
|
|
36
38
|
type ConcreteFunctionDefinition,
|
|
@@ -40,6 +42,7 @@ import {
|
|
|
40
42
|
type ObserverContext,
|
|
41
43
|
type ValueSpecification,
|
|
42
44
|
type TestAssertion,
|
|
45
|
+
type AccessorOwner,
|
|
43
46
|
FunctionParameterValue,
|
|
44
47
|
VariableExpression,
|
|
45
48
|
FunctionTest,
|
|
@@ -58,9 +61,19 @@ import {
|
|
|
58
61
|
observe_ValueSpecification,
|
|
59
62
|
buildLambdaVariableExpressions,
|
|
60
63
|
EqualTo,
|
|
64
|
+
EqualToRelation,
|
|
65
|
+
RelationElement,
|
|
66
|
+
RelationRowTestData,
|
|
67
|
+
observe_RelationElement,
|
|
68
|
+
observe_RelationRowTestData,
|
|
61
69
|
ModelStore,
|
|
62
70
|
RelationElementsData,
|
|
63
71
|
CORE_PURE_PATH,
|
|
72
|
+
type Accessor,
|
|
73
|
+
DataProductAccessor,
|
|
74
|
+
IngestionAccessor,
|
|
75
|
+
RelationalStoreAccessor,
|
|
76
|
+
V1_buildRelationElementsDataFromAccessors,
|
|
64
77
|
} from '@finos/legend-graph';
|
|
65
78
|
import {
|
|
66
79
|
TestablePackageableElementEditorState,
|
|
@@ -68,6 +81,7 @@ import {
|
|
|
68
81
|
TestableTestSuiteEditorState,
|
|
69
82
|
} from '../../testable/TestableEditorState.js';
|
|
70
83
|
import { EmbeddedDataEditorState } from '../../data/DataEditorState.js';
|
|
84
|
+
import { RelationElementsDataState } from '../../data/EmbeddedDataState.js';
|
|
71
85
|
import {
|
|
72
86
|
functionTestable_deleteDataStore,
|
|
73
87
|
functionTestable_setEmbeddedData,
|
|
@@ -207,6 +221,69 @@ export class FunctionStoreTestDataState {
|
|
|
207
221
|
hideSource: true,
|
|
208
222
|
},
|
|
209
223
|
);
|
|
224
|
+
this.initAccessorOptions();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private initAccessorOptions(): void {
|
|
228
|
+
const embeddedDataState = this.embeddedEditorState.embeddedDataState;
|
|
229
|
+
if (!(embeddedDataState instanceof RelationElementsDataState)) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this.refreshAccessorOptions(embeddedDataState).catch(noop());
|
|
233
|
+
embeddedDataState.setRefreshAccessorOptions(() =>
|
|
234
|
+
this.refreshAccessorOptions(embeddedDataState),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private async refreshAccessorOptions(
|
|
239
|
+
embeddedDataState: RelationElementsDataState,
|
|
240
|
+
): Promise<void> {
|
|
241
|
+
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) {
|
|
249
|
+
embeddedDataState.setAccessorOptions(undefined, undefined);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const firstAccessor = parentAccessors[0];
|
|
253
|
+
if (!firstAccessor) {
|
|
254
|
+
embeddedDataState.setAccessorOptions(undefined, undefined);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
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) {
|
|
274
|
+
for (const relState of embeddedDataState.relationElementStates) {
|
|
275
|
+
const rel = relState.relationElement;
|
|
276
|
+
if (rel.columns.length === 0) {
|
|
277
|
+
const key = rel.paths[rel.paths.length - 1];
|
|
278
|
+
const cols = key ? columnOverrides.get(key) : undefined;
|
|
279
|
+
if (cols) {
|
|
280
|
+
rel.columns = cols;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
embeddedDataState.setAccessorOptions(options, typeLabel);
|
|
210
287
|
}
|
|
211
288
|
|
|
212
289
|
setDataElementModal(val: boolean): void {
|
|
@@ -532,6 +609,7 @@ class FunctionTestDataState {
|
|
|
532
609
|
selectedDataState: FunctionStoreTestDataState | undefined;
|
|
533
610
|
dataHolder: FunctionTestSuite;
|
|
534
611
|
showNewModal = false;
|
|
612
|
+
showAddElementModal = false;
|
|
535
613
|
|
|
536
614
|
constructor(
|
|
537
615
|
editorStore: EditorStore,
|
|
@@ -542,9 +620,12 @@ class FunctionTestDataState {
|
|
|
542
620
|
selectedDataState: observable,
|
|
543
621
|
dataHolder: observable,
|
|
544
622
|
showNewModal: observable,
|
|
623
|
+
showAddElementModal: observable,
|
|
545
624
|
initDefaultStore: action,
|
|
546
625
|
setShowModal: action,
|
|
626
|
+
setShowAddElementModal: action,
|
|
547
627
|
deleteStoreTestData: action,
|
|
628
|
+
addDataElement: action,
|
|
548
629
|
openStoreTestData: action,
|
|
549
630
|
});
|
|
550
631
|
this.editorStore = editorStore;
|
|
@@ -566,6 +647,49 @@ class FunctionTestDataState {
|
|
|
566
647
|
this.showNewModal = val;
|
|
567
648
|
}
|
|
568
649
|
|
|
650
|
+
setShowAddElementModal(val: boolean): void {
|
|
651
|
+
this.showAddElementModal = val;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
get existingElementPaths(): string[] {
|
|
655
|
+
return (this.dataHolder.testData ?? []).map((td) => td.element.value.path);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
get availableElementsToAdd(): { path: string }[] {
|
|
659
|
+
const accessors =
|
|
660
|
+
this.functionTestableState.resolvedIngestOrDataProductAccessors;
|
|
661
|
+
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 }));
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
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) {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
const element =
|
|
680
|
+
this.editorStore.graphManagerState.graph.getElement(elementPath);
|
|
681
|
+
const data = new FunctionTestData();
|
|
682
|
+
data.element = PackageableElementExplicitReference.create(
|
|
683
|
+
element as AccessorOwner,
|
|
684
|
+
);
|
|
685
|
+
data.data = V1_buildRelationElementsDataFromAccessors(group);
|
|
686
|
+
if (!this.dataHolder.testData) {
|
|
687
|
+
this.dataHolder.testData = [];
|
|
688
|
+
}
|
|
689
|
+
this.dataHolder.testData.push(data);
|
|
690
|
+
this.openStoreTestData(data);
|
|
691
|
+
}
|
|
692
|
+
|
|
569
693
|
deleteStoreTestData(val: FunctionTestData): void {
|
|
570
694
|
functionTestable_deleteDataStore(this.dataHolder, val);
|
|
571
695
|
this.initDefaultStore();
|
|
@@ -580,26 +704,62 @@ class FunctionTestDataState {
|
|
|
580
704
|
}
|
|
581
705
|
}
|
|
582
706
|
|
|
583
|
-
export const createFunctionTest = (
|
|
707
|
+
export const createFunctionTest = async (
|
|
584
708
|
id: string,
|
|
585
709
|
observerContext: ObserverContext,
|
|
586
710
|
containsRuntime: boolean,
|
|
587
711
|
functionDefinition: ConcreteFunctionDefinition,
|
|
588
712
|
editorStore: EditorStore,
|
|
589
713
|
suite?: FunctionTestSuite | undefined,
|
|
590
|
-
): FunctionTest => {
|
|
714
|
+
): Promise<FunctionTest> => {
|
|
591
715
|
const funcionTest = new FunctionTest();
|
|
592
716
|
funcionTest.id = id;
|
|
593
717
|
funcionTest.assertions = [];
|
|
594
718
|
let _assertion: TestAssertion;
|
|
595
|
-
|
|
719
|
+
const type = functionDefinition.returnType.value.rawType;
|
|
720
|
+
if (
|
|
721
|
+
type.path === CORE_PURE_PATH.RELATION ||
|
|
722
|
+
type.path === CORE_PURE_PATH.TABULAR_DATASET
|
|
723
|
+
) {
|
|
724
|
+
const assertion = new EqualToRelation();
|
|
725
|
+
assertion.id = DEFAULT_TEST_ASSERTION_ID;
|
|
726
|
+
const expectedRelElement = new RelationElement();
|
|
727
|
+
expectedRelElement.paths = [];
|
|
728
|
+
let inferredColumns: string[] = [];
|
|
729
|
+
if (type.path === CORE_PURE_PATH.RELATION) {
|
|
730
|
+
try {
|
|
731
|
+
const rawLambda = new RawLambda(
|
|
732
|
+
functionDefinition.parameters.map((_param) =>
|
|
733
|
+
editorStore.graphManagerState.graphManager.serializeRawValueSpecification(
|
|
734
|
+
_param,
|
|
735
|
+
),
|
|
736
|
+
),
|
|
737
|
+
functionDefinition.expressionSequence,
|
|
738
|
+
);
|
|
739
|
+
const relationTypeMetadata =
|
|
740
|
+
await editorStore.graphManagerState.graphManager.getLambdaRelationType(
|
|
741
|
+
rawLambda,
|
|
742
|
+
editorStore.graphManagerState.graph,
|
|
743
|
+
);
|
|
744
|
+
inferredColumns = relationTypeMetadata.columns.map((col) => col.name);
|
|
745
|
+
} catch {
|
|
746
|
+
// best-effort: leave columns empty
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
expectedRelElement.columns = inferredColumns;
|
|
750
|
+
const emptyRow = observe_RelationRowTestData(new RelationRowTestData());
|
|
751
|
+
emptyRow.values = inferredColumns.map(() => '');
|
|
752
|
+
expectedRelElement.rows = [emptyRow];
|
|
753
|
+
observe_RelationElement(expectedRelElement);
|
|
754
|
+
assertion.expected = expectedRelElement;
|
|
755
|
+
_assertion = assertion;
|
|
756
|
+
} else if (containsRuntime) {
|
|
596
757
|
_assertion = createDefaultEqualToJSONTestAssertion(
|
|
597
758
|
DEFAULT_TEST_ASSERTION_ID,
|
|
598
759
|
);
|
|
599
760
|
} else {
|
|
600
761
|
const equalTo = new EqualTo();
|
|
601
762
|
equalTo.id = DEFAULT_TEST_ASSERTION_ID;
|
|
602
|
-
const type = functionDefinition.returnType.value.rawType;
|
|
603
763
|
const valSpec = buildDefaultInstanceValue(
|
|
604
764
|
editorStore.graphManagerState.graph,
|
|
605
765
|
type,
|
|
@@ -652,7 +812,7 @@ export class FunctionTestSuiteState extends TestableTestSuiteEditorState {
|
|
|
652
812
|
deleteTest: action,
|
|
653
813
|
buildTestStates: action,
|
|
654
814
|
setShowModal: action,
|
|
655
|
-
addNewTest:
|
|
815
|
+
addNewTest: flow,
|
|
656
816
|
});
|
|
657
817
|
this.functionTestableState = functionTestableState;
|
|
658
818
|
this.suite = suite;
|
|
@@ -682,15 +842,15 @@ export class FunctionTestSuiteState extends TestableTestSuiteEditorState {
|
|
|
682
842
|
return undefined;
|
|
683
843
|
}
|
|
684
844
|
|
|
685
|
-
addNewTest(id: string): void {
|
|
686
|
-
const test = createFunctionTest(
|
|
845
|
+
*addNewTest(id: string): GeneratorFn<void> {
|
|
846
|
+
const test = (yield createFunctionTest(
|
|
687
847
|
id,
|
|
688
848
|
this.editorStore.changeDetectionState.observerContext,
|
|
689
849
|
this.functionTestableState.containsRuntime,
|
|
690
850
|
this.functionTestableState.function,
|
|
691
851
|
this.editorStore,
|
|
692
852
|
this.suite,
|
|
693
|
-
);
|
|
853
|
+
)) as FunctionTest;
|
|
694
854
|
testSuite_addTest(
|
|
695
855
|
this.suite,
|
|
696
856
|
test,
|
|
@@ -711,6 +871,7 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
|
|
|
711
871
|
declare runningSuite: FunctionTestSuite | undefined;
|
|
712
872
|
|
|
713
873
|
createSuiteModal = false;
|
|
874
|
+
cachedAccessors: Accessor[] = [];
|
|
714
875
|
|
|
715
876
|
constructor(functionEditorState: FunctionEditorState) {
|
|
716
877
|
super(functionEditorState, functionEditorState.functionElement);
|
|
@@ -722,6 +883,7 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
|
|
|
722
883
|
runningSuite: observable,
|
|
723
884
|
testableComponentToRename: observable,
|
|
724
885
|
createSuiteModal: observable,
|
|
886
|
+
cachedAccessors: observable,
|
|
725
887
|
init: action,
|
|
726
888
|
buildTestSuiteState: action,
|
|
727
889
|
deleteTestSuite: action,
|
|
@@ -730,6 +892,8 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
|
|
|
730
892
|
setRenameComponent: action,
|
|
731
893
|
clearTestResultsForSuite: action,
|
|
732
894
|
setCreateSuite: action,
|
|
895
|
+
resolveAccessors: flow,
|
|
896
|
+
createSuite: flow,
|
|
733
897
|
runTestable: flow,
|
|
734
898
|
runSuite: flow,
|
|
735
899
|
runAllFailingSuites: flow,
|
|
@@ -750,6 +914,36 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
|
|
|
750
914
|
return Boolean(this.associatedRuntimes?.length);
|
|
751
915
|
}
|
|
752
916
|
|
|
917
|
+
get resolvedIngestOrDataProductAccessors(): Accessor[] {
|
|
918
|
+
return this.cachedAccessors.filter(
|
|
919
|
+
(a) => a instanceof DataProductAccessor || a instanceof IngestionAccessor,
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
private buildRawLambdaFromFunction(): RawLambda {
|
|
924
|
+
return new RawLambda(
|
|
925
|
+
this.function.parameters.map((_param) =>
|
|
926
|
+
this.editorStore.graphManagerState.graphManager.serializeRawValueSpecification(
|
|
927
|
+
_param,
|
|
928
|
+
),
|
|
929
|
+
),
|
|
930
|
+
this.function.expressionSequence,
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
*resolveAccessors(): GeneratorFn<void> {
|
|
935
|
+
try {
|
|
936
|
+
const rawLambda = this.buildRawLambdaFromFunction();
|
|
937
|
+
this.cachedAccessors =
|
|
938
|
+
(yield this.editorStore.graphManagerState.graphManager.collectAccessorsInRawLambda(
|
|
939
|
+
rawLambda,
|
|
940
|
+
this.editorStore.graphManagerState.graph,
|
|
941
|
+
)) as Accessor[];
|
|
942
|
+
} catch {
|
|
943
|
+
this.cachedAccessors = [];
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
753
947
|
override init(): void {
|
|
754
948
|
if (!this.selectedTestSuite) {
|
|
755
949
|
const suite = this.function.tests[0];
|
|
@@ -757,84 +951,125 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
|
|
|
757
951
|
? this.buildTestSuiteState(suite)
|
|
758
952
|
: undefined;
|
|
759
953
|
}
|
|
954
|
+
flowResult(this.resolveAccessors()).catch(noop);
|
|
760
955
|
}
|
|
761
956
|
|
|
762
957
|
setCreateSuite(val: boolean): void {
|
|
763
958
|
this.createSuiteModal = val;
|
|
764
959
|
}
|
|
765
960
|
|
|
766
|
-
createSuite(suiteName: string, testName: string): void {
|
|
961
|
+
*createSuite(suiteName: string, testName: string): GeneratorFn<void> {
|
|
767
962
|
const functionSuite = new FunctionTestSuite();
|
|
768
963
|
functionSuite.id = suiteName;
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
)
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
...engineRuntime.connectionStores
|
|
802
|
-
.map((e) => e.storePointers.map((sPt) => sPt.value))
|
|
803
|
-
.flat(),
|
|
804
|
-
].filter(isNonNullable);
|
|
805
|
-
assertTrue(Boolean(stores.length), 'No runtime store found');
|
|
806
|
-
assertTrue(
|
|
807
|
-
stores.length === 1,
|
|
808
|
-
'Only one store supported in runtime for function tests',
|
|
964
|
+
|
|
965
|
+
yield flowResult(this.resolveAccessors());
|
|
966
|
+
|
|
967
|
+
const ingestOrDataProductAccessors =
|
|
968
|
+
this.resolvedIngestOrDataProductAccessors;
|
|
969
|
+
const databaseAccessors = this.cachedAccessors.filter(
|
|
970
|
+
(a) => a instanceof RelationalStoreAccessor,
|
|
971
|
+
);
|
|
972
|
+
|
|
973
|
+
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
|
+
},
|
|
809
996
|
);
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
997
|
+
} else {
|
|
998
|
+
// No ingest/data product accessors found — try runtime-based approach
|
|
999
|
+
const engineRuntimes = this.associatedRuntimes;
|
|
1000
|
+
if (engineRuntimes?.length) {
|
|
1001
|
+
assertTrue(
|
|
1002
|
+
engineRuntimes.length === 1,
|
|
1003
|
+
`Function Test Suite Only supports One Runtime at this time. Found ${engineRuntimes.length}`,
|
|
1004
|
+
);
|
|
1005
|
+
const engineRuntime = guaranteeNonNullable(engineRuntimes[0]);
|
|
1006
|
+
assertTrue(
|
|
1007
|
+
!(
|
|
1008
|
+
engineRuntime.connectionStores.length &&
|
|
1009
|
+
engineRuntime.connections.length
|
|
1010
|
+
),
|
|
1011
|
+
`Runtime found has two connection types defined. Please use connection stores only`,
|
|
823
1012
|
);
|
|
1013
|
+
const stores = [
|
|
1014
|
+
...engineRuntime.connections
|
|
1015
|
+
.map((e) =>
|
|
1016
|
+
e.storeConnections.map((s) => s.connection.store?.value).flat(),
|
|
1017
|
+
)
|
|
1018
|
+
.flat(),
|
|
1019
|
+
...engineRuntime.connectionStores
|
|
1020
|
+
.map((e) => e.storePointers.map((sPt) => sPt.value))
|
|
1021
|
+
.flat(),
|
|
1022
|
+
].filter(isNonNullable);
|
|
1023
|
+
assertTrue(Boolean(stores.length), 'No runtime store found');
|
|
1024
|
+
assertTrue(
|
|
1025
|
+
stores.length === 1,
|
|
1026
|
+
'Only one store supported in runtime for function tests',
|
|
1027
|
+
);
|
|
1028
|
+
const store = guaranteeNonNullable(stores[0]);
|
|
1029
|
+
const data = new FunctionTestData();
|
|
1030
|
+
if (store instanceof Database) {
|
|
1031
|
+
const relation = new RelationElementsData();
|
|
1032
|
+
data.element = PackageableElementExplicitReference.create(store);
|
|
1033
|
+
data.data = relation;
|
|
1034
|
+
} else if (store instanceof ModelStore) {
|
|
1035
|
+
const modelStoreData = createBareExternalFormat();
|
|
1036
|
+
data.element = PackageableElementExplicitReference.create(store);
|
|
1037
|
+
data.data = modelStoreData;
|
|
1038
|
+
} else {
|
|
1039
|
+
throw new UnsupportedOperationError(
|
|
1040
|
+
`function test store data does not support store: ${store.path}`,
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
1043
|
+
functionSuite.testData = [data];
|
|
1044
|
+
} else {
|
|
1045
|
+
const type = this.function.returnType.value.rawType;
|
|
1046
|
+
if (
|
|
1047
|
+
type.path === CORE_PURE_PATH.RELATION ||
|
|
1048
|
+
type.path === CORE_PURE_PATH.TABULAR_DATASET
|
|
1049
|
+
) {
|
|
1050
|
+
this.editorStore.applicationStore.notificationService.notifyError(
|
|
1051
|
+
`Unable to create function test suite: no runtime or accessors found, or they could not be resolved`,
|
|
1052
|
+
);
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
824
1055
|
}
|
|
825
|
-
functionSuite.testData = [data];
|
|
826
|
-
} catch (error) {
|
|
827
|
-
assertErrorThrown(error);
|
|
828
|
-
this.editorStore.applicationStore.notificationService.notifyError(
|
|
829
|
-
`Unable to create function test suite: ${error.message}`,
|
|
830
|
-
);
|
|
831
|
-
return;
|
|
832
1056
|
}
|
|
1057
|
+
} catch (error) {
|
|
1058
|
+
assertErrorThrown(error);
|
|
1059
|
+
this.editorStore.applicationStore.notificationService.notifyError(
|
|
1060
|
+
`Unable to create function test suite: ${error.message}`,
|
|
1061
|
+
);
|
|
1062
|
+
return;
|
|
833
1063
|
}
|
|
834
|
-
|
|
1064
|
+
|
|
1065
|
+
const hasTestData =
|
|
1066
|
+
this.containsRuntime ||
|
|
1067
|
+
ingestOrDataProductAccessors.length > 0 ||
|
|
1068
|
+
databaseAccessors.length > 0;
|
|
1069
|
+
yield createFunctionTest(
|
|
835
1070
|
testName,
|
|
836
1071
|
this.editorStore.changeDetectionState.observerContext,
|
|
837
|
-
|
|
1072
|
+
hasTestData,
|
|
838
1073
|
this.function,
|
|
839
1074
|
this.editorStore,
|
|
840
1075
|
functionSuite,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
type WorkspaceType,
|
|
43
43
|
} from '@finos/legend-server-sdlc';
|
|
44
44
|
import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js';
|
|
45
|
+
import { LegendStudioUserDataHelper } from '../../../__lib__/LegendStudioUserDataHelper.js';
|
|
45
46
|
|
|
46
47
|
export enum PROJECT_OVERVIEW_ACTIVITY_MODE {
|
|
47
48
|
RELEASE = 'RELEASE',
|
|
@@ -155,6 +156,19 @@ export class ProjectOverviewState {
|
|
|
155
156
|
this.projectWorkspaces = this.projectWorkspaces.filter(
|
|
156
157
|
(w) => !areWorkspacesEquivalent(workspace, w),
|
|
157
158
|
);
|
|
159
|
+
// Drop the deleted workspace from the recents cache so the workspace
|
|
160
|
+
// setup screen doesn't keep offering a dead link. Patch workspaces are
|
|
161
|
+
// never cached, so this is a no-op for them.
|
|
162
|
+
if (workspace.source === undefined) {
|
|
163
|
+
LegendStudioUserDataHelper.workspaceSetup_removeRecentWorkspace(
|
|
164
|
+
this.editorStore.applicationStore.userDataService,
|
|
165
|
+
{
|
|
166
|
+
projectId: this.sdlcState.activeProject.projectId,
|
|
167
|
+
workspaceId: workspace.workspaceId,
|
|
168
|
+
workspaceType: workspace.workspaceType,
|
|
169
|
+
},
|
|
170
|
+
);
|
|
171
|
+
}
|
|
158
172
|
// redirect to home page if current workspace is deleted
|
|
159
173
|
if (
|
|
160
174
|
areWorkspacesEquivalent(
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
import type { EditorStore } from '../EditorStore.js';
|
|
26
26
|
import type { EditorSDLCState } from '../EditorSDLCState.js';
|
|
27
27
|
import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js';
|
|
28
|
+
import { LegendStudioUserDataHelper } from '../../../__lib__/LegendStudioUserDataHelper.js';
|
|
28
29
|
import {
|
|
29
30
|
type GeneratorFn,
|
|
30
31
|
type PlainObject,
|
|
@@ -402,6 +403,19 @@ export class WorkspaceReviewState {
|
|
|
402
403
|
review.id,
|
|
403
404
|
{ message: `${review.title} [review]` },
|
|
404
405
|
);
|
|
406
|
+
// Committing a review deletes the workspace on SDLC. Drop it from
|
|
407
|
+
// the recents cache so the workspace setup screen doesn't keep
|
|
408
|
+
// offering a dead link. Patch workspaces are never cached.
|
|
409
|
+
if (this.sdlcState.activePatch === undefined) {
|
|
410
|
+
LegendStudioUserDataHelper.workspaceSetup_removeRecentWorkspace(
|
|
411
|
+
this.editorStore.applicationStore.userDataService,
|
|
412
|
+
{
|
|
413
|
+
projectId: this.sdlcState.activeProject.projectId,
|
|
414
|
+
workspaceId: this.sdlcState.activeWorkspace.workspaceId,
|
|
415
|
+
workspaceType: this.sdlcState.activeWorkspace.workspaceType,
|
|
416
|
+
},
|
|
417
|
+
);
|
|
418
|
+
}
|
|
405
419
|
this.editorStore.applicationStore.alertService.setActionAlertInfo({
|
|
406
420
|
message: 'Committed review successfully',
|
|
407
421
|
prompt:
|