@finos/legend-application-query 13.8.7 → 13.8.9
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__/LegendQueryNavigation.d.ts +16 -2
- package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
- package/lib/__lib__/LegendQueryNavigation.js +21 -2
- package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.d.ts +2 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.js +13 -0
- package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
- package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
- package/lib/components/LegendQueryWebApplication.js +2 -1
- package/lib/components/LegendQueryWebApplication.js.map +1 -1
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts +14 -2
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts.map +1 -1
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js +93 -7
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js.map +1 -1
- package/lib/components/data-product/DataProductInfo.d.ts.map +1 -1
- package/lib/components/data-product/DataProductInfo.js +1 -1
- package/lib/components/data-product/DataProductInfo.js.map +1 -1
- package/lib/components/data-product/DataProductSampleQueryCreator.d.ts +19 -0
- package/lib/components/data-product/DataProductSampleQueryCreator.d.ts.map +1 -0
- package/lib/components/data-product/DataProductSampleQueryCreator.js +53 -0
- package/lib/components/data-product/DataProductSampleQueryCreator.js.map +1 -0
- package/lib/components/data-product/DataProductSampleQueryPanel.d.ts +23 -0
- package/lib/components/data-product/DataProductSampleQueryPanel.d.ts.map +1 -0
- package/lib/components/data-product/DataProductSampleQueryPanel.js +95 -0
- package/lib/components/data-product/DataProductSampleQueryPanel.js.map +1 -0
- package/lib/index.css +1 -1
- package/lib/light-mode.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/BaseTemplateQueryCreatorStore.d.ts +68 -0
- package/lib/stores/BaseTemplateQueryCreatorStore.d.ts.map +1 -0
- package/lib/stores/BaseTemplateQueryCreatorStore.js +120 -0
- package/lib/stores/BaseTemplateQueryCreatorStore.js.map +1 -0
- package/lib/stores/QueryEditorStore.d.ts +1 -1
- package/lib/stores/QueryEditorStore.d.ts.map +1 -1
- package/lib/stores/QueryEditorStore.js +43 -29
- package/lib/stores/QueryEditorStore.js.map +1 -1
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts +37 -0
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts.map +1 -0
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js +60 -0
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js.map +1 -0
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.d.ts.map +1 -1
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js +9 -8
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js.map +1 -1
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts +12 -2
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts.map +1 -1
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js +22 -2
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js.map +1 -1
- package/lib/stores/data-space/DataProductQueryCreatorStore.js +1 -1
- package/lib/stores/data-space/DataProductQueryCreatorStore.js.map +1 -1
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts +14 -18
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts.map +1 -1
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js +15 -80
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js.map +1 -1
- package/package.json +13 -13
- package/src/__lib__/LegendQueryNavigation.ts +43 -5
- package/src/components/Core_LegendQueryApplicationPlugin.tsx +17 -0
- package/src/components/LegendQueryWebApplication.tsx +5 -0
- package/src/components/__test-utils__/QueryEditorComponentTestUtils.tsx +237 -5
- package/src/components/data-product/DataProductInfo.tsx +12 -10
- package/src/components/data-product/DataProductSampleQueryCreator.tsx +114 -0
- package/src/components/data-product/DataProductSampleQueryPanel.tsx +219 -0
- package/src/stores/BaseTemplateQueryCreatorStore.ts +203 -0
- package/src/stores/QueryEditorStore.ts +64 -44
- package/src/stores/data-product/DataProductSampleQueryCreatorStore.ts +135 -0
- package/src/stores/data-product/query-builder/DataProductArtifactHelper.ts +12 -8
- package/src/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.ts +36 -4
- package/src/stores/data-space/DataProductQueryCreatorStore.ts +1 -1
- package/src/stores/data-space/DataSpaceTemplateQueryCreatorStore.ts +31 -126
- package/tsconfig.json +4 -0
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
QueryDataProductNativeExecutionContextInfo,
|
|
43
43
|
ModelAccessPointGroup,
|
|
44
44
|
V1_PureGraphManager,
|
|
45
|
+
type V1_DataProductArtifact,
|
|
45
46
|
} from '@finos/legend-graph';
|
|
46
47
|
import { DepotServerClient } from '@finos/legend-server-depot';
|
|
47
48
|
import {
|
|
@@ -76,6 +77,7 @@ import {
|
|
|
76
77
|
} from '@finos/legend-application/browser';
|
|
77
78
|
import {
|
|
78
79
|
generateExistingQueryEditorRoute,
|
|
80
|
+
generateDataProductSampleQueryRoute,
|
|
79
81
|
LEGEND_QUERY_ROUTE_PATTERN,
|
|
80
82
|
} from '../../__lib__/LegendQueryNavigation.js';
|
|
81
83
|
import {
|
|
@@ -90,6 +92,8 @@ import {
|
|
|
90
92
|
import { LegendQueryDataProductQueryBuilderState } from '../../stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js';
|
|
91
93
|
import { DataProductSelectorState } from '../../stores/data-space/DataProductSelectorState.js';
|
|
92
94
|
import { DataSpaceTemplateQueryCreatorStore } from '../../stores/data-space/DataSpaceTemplateQueryCreatorStore.js';
|
|
95
|
+
import { DataProductSampleQueryCreatorStore } from '../../stores/data-product/DataProductSampleQueryCreatorStore.js';
|
|
96
|
+
import { DataProductSampleQueryCreator } from '../data-product/DataProductSampleQueryCreator.js';
|
|
93
97
|
|
|
94
98
|
const TEST_QUERY_ID = 'test-query-id';
|
|
95
99
|
const TEST_GROUP_ID = 'test-group';
|
|
@@ -97,6 +101,8 @@ const TEST_ARTIFACT_ID = 'test-artifact';
|
|
|
97
101
|
const TEST_VERSION_ID = 'test-version';
|
|
98
102
|
const TEST_TEMPLATE_QUERY_ID = 'templateQuery';
|
|
99
103
|
const TEST_DATA_SPACE_PATH = 'domain::COVIDDatapace';
|
|
104
|
+
const TEST_SAMPLE_QUERY_ID = 'sampleQuery';
|
|
105
|
+
const TEST_DATA_PRODUCT_PATH = 'test::MyDataProduct';
|
|
100
106
|
export const TEST_QUERY_NAME = 'MyTestQuery';
|
|
101
107
|
|
|
102
108
|
export const TEST__provideMockedQueryEditorStore = (customization?: {
|
|
@@ -775,13 +781,15 @@ export const TEST__setUpDataProductExistingQueryEditor = async (
|
|
|
775
781
|
async () => {
|
|
776
782
|
/* no-op for tests */
|
|
777
783
|
},
|
|
784
|
+
async () => {
|
|
785
|
+
throw new Error('Not implemented in tests');
|
|
786
|
+
},
|
|
778
787
|
new DataProductSelectorState(
|
|
779
788
|
MOCK__editorStore.depotServerClient,
|
|
780
789
|
MOCK__editorStore.applicationStore,
|
|
781
790
|
),
|
|
782
791
|
undefined,
|
|
783
792
|
undefined,
|
|
784
|
-
undefined,
|
|
785
793
|
MOCK__editorStore.applicationStore.config.options.queryBuilderConfig,
|
|
786
794
|
{
|
|
787
795
|
groupId: 'test.group',
|
|
@@ -790,7 +798,11 @@ export const TEST__setUpDataProductExistingQueryEditor = async (
|
|
|
790
798
|
dataProduct: dataProductPath,
|
|
791
799
|
},
|
|
792
800
|
);
|
|
793
|
-
mockQueryBuilderState.initWithDataProduct(
|
|
801
|
+
mockQueryBuilderState.initWithDataProduct(
|
|
802
|
+
dataProduct,
|
|
803
|
+
undefined,
|
|
804
|
+
executionState,
|
|
805
|
+
);
|
|
794
806
|
|
|
795
807
|
MOCK__editorStore.buildGraph = createMock();
|
|
796
808
|
MOCK__editorStore.buildFullGraph = createMock();
|
|
@@ -841,6 +853,7 @@ export const TEST__setUpDataProductNativeExistingQueryEditor = async (
|
|
|
841
853
|
executionKey: string,
|
|
842
854
|
lambda: RawLambda,
|
|
843
855
|
entities: PlainObject<Entity>[],
|
|
856
|
+
artifact?: V1_DataProductArtifact | undefined,
|
|
844
857
|
): Promise<{
|
|
845
858
|
renderResult: RenderResult;
|
|
846
859
|
queryBuilderState: QueryBuilderState;
|
|
@@ -970,20 +983,22 @@ export const TEST__setUpDataProductNativeExistingQueryEditor = async (
|
|
|
970
983
|
QueryBuilderDataBrowserWorkflow.INSTANCE,
|
|
971
984
|
new QueryBuilderActionConfig_QueryApplication(MOCK__editorStore),
|
|
972
985
|
dataProduct,
|
|
973
|
-
|
|
986
|
+
artifact,
|
|
974
987
|
executionState,
|
|
975
988
|
MOCK__editorStore.depotServerClient,
|
|
976
989
|
{ groupId: 'test.group', artifactId: 'test-artifact', versionId: '0.0.0' },
|
|
977
990
|
async () => {
|
|
978
991
|
/* no-op for tests */
|
|
979
992
|
},
|
|
993
|
+
async () => {
|
|
994
|
+
throw new Error('Not implemented in tests');
|
|
995
|
+
},
|
|
980
996
|
new DataProductSelectorState(
|
|
981
997
|
MOCK__editorStore.depotServerClient,
|
|
982
998
|
MOCK__editorStore.applicationStore,
|
|
983
999
|
),
|
|
984
1000
|
undefined,
|
|
985
1001
|
undefined,
|
|
986
|
-
undefined,
|
|
987
1002
|
MOCK__editorStore.applicationStore.config.options.queryBuilderConfig,
|
|
988
1003
|
{
|
|
989
1004
|
groupId: 'test.group',
|
|
@@ -992,7 +1007,11 @@ export const TEST__setUpDataProductNativeExistingQueryEditor = async (
|
|
|
992
1007
|
dataProduct: dataProductPath,
|
|
993
1008
|
},
|
|
994
1009
|
);
|
|
995
|
-
mockQueryBuilderState.initWithDataProduct(
|
|
1010
|
+
mockQueryBuilderState.initWithDataProduct(
|
|
1011
|
+
dataProduct,
|
|
1012
|
+
undefined,
|
|
1013
|
+
executionState,
|
|
1014
|
+
);
|
|
996
1015
|
|
|
997
1016
|
MOCK__editorStore.buildGraph = createMock();
|
|
998
1017
|
MOCK__editorStore.buildFullGraph = createMock();
|
|
@@ -1036,3 +1055,216 @@ export const TEST__setUpDataProductNativeExistingQueryEditor = async (
|
|
|
1036
1055
|
),
|
|
1037
1056
|
};
|
|
1038
1057
|
};
|
|
1058
|
+
|
|
1059
|
+
export const TEST__provideMockedDataProductSampleQueryCreatorStore =
|
|
1060
|
+
(customization?: {
|
|
1061
|
+
mock?: DataProductSampleQueryCreatorStore;
|
|
1062
|
+
applicationStore?: LegendQueryApplicationStore;
|
|
1063
|
+
pluginManager?: LegendQueryPluginManager;
|
|
1064
|
+
extraPlugins?: AbstractPlugin[];
|
|
1065
|
+
extraPresets?: AbstractPreset[];
|
|
1066
|
+
}): DataProductSampleQueryCreatorStore => {
|
|
1067
|
+
const pluginManager =
|
|
1068
|
+
customization?.pluginManager ?? LegendQueryPluginManager.create();
|
|
1069
|
+
pluginManager
|
|
1070
|
+
.usePlugins([
|
|
1071
|
+
new Core_LegendQueryApplicationPlugin(),
|
|
1072
|
+
...(customization?.extraPlugins ?? []),
|
|
1073
|
+
])
|
|
1074
|
+
.usePresets([...(customization?.extraPresets ?? [])])
|
|
1075
|
+
.install();
|
|
1076
|
+
const applicationStore =
|
|
1077
|
+
customization?.applicationStore ??
|
|
1078
|
+
new ApplicationStore(
|
|
1079
|
+
TEST__getTestLegendQueryApplicationConfig(),
|
|
1080
|
+
pluginManager,
|
|
1081
|
+
);
|
|
1082
|
+
const depotServerClient = new DepotServerClient({
|
|
1083
|
+
serverUrl: applicationStore.config.depotServerUrl,
|
|
1084
|
+
});
|
|
1085
|
+
depotServerClient.setTracerService(applicationStore.tracerService);
|
|
1086
|
+
const value =
|
|
1087
|
+
customization?.mock ??
|
|
1088
|
+
new DataProductSampleQueryCreatorStore(
|
|
1089
|
+
applicationStore,
|
|
1090
|
+
depotServerClient,
|
|
1091
|
+
TEST_GROUP_ID,
|
|
1092
|
+
TEST_ARTIFACT_ID,
|
|
1093
|
+
TEST_VERSION_ID,
|
|
1094
|
+
TEST_DATA_PRODUCT_PATH,
|
|
1095
|
+
TEST_SAMPLE_QUERY_ID,
|
|
1096
|
+
{ fips: 'value' },
|
|
1097
|
+
);
|
|
1098
|
+
const MOCK__QueryEditorStoreProvider = require('../QueryEditorStoreProvider.js'); // eslint-disable-line @typescript-eslint/no-require-imports,@typescript-eslint/no-unsafe-assignment
|
|
1099
|
+
MOCK__QueryEditorStoreProvider.useQueryEditorStore = createMock();
|
|
1100
|
+
MOCK__QueryEditorStoreProvider.useQueryEditorStore.mockReturnValue(value);
|
|
1101
|
+
return value;
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
export const TEST__setUpDataProductSampleQueryEditor = async (
|
|
1105
|
+
MOCK__editorStore: DataProductSampleQueryCreatorStore,
|
|
1106
|
+
dataProductPath: string,
|
|
1107
|
+
executionKey: string,
|
|
1108
|
+
lambda: RawLambda,
|
|
1109
|
+
entities: PlainObject<Entity>[],
|
|
1110
|
+
artifact: V1_DataProductArtifact,
|
|
1111
|
+
): Promise<{
|
|
1112
|
+
renderResult: RenderResult;
|
|
1113
|
+
queryBuilderState: QueryBuilderState;
|
|
1114
|
+
}> => {
|
|
1115
|
+
const projectData = {
|
|
1116
|
+
id: 'test-id',
|
|
1117
|
+
groupId: MOCK__editorStore.groupId,
|
|
1118
|
+
artifactId: MOCK__editorStore.artifactId,
|
|
1119
|
+
projectId: 'test-project-id',
|
|
1120
|
+
versions: [MOCK__editorStore.versionId],
|
|
1121
|
+
latestVersion: MOCK__editorStore.versionId,
|
|
1122
|
+
};
|
|
1123
|
+
|
|
1124
|
+
const graphManagerState = MOCK__editorStore.graphManagerState;
|
|
1125
|
+
|
|
1126
|
+
await graphManagerState.graphManager.initialize({
|
|
1127
|
+
env: 'test',
|
|
1128
|
+
tabSize: 2,
|
|
1129
|
+
clientConfig: {},
|
|
1130
|
+
});
|
|
1131
|
+
await graphManagerState.initializeSystem();
|
|
1132
|
+
await graphManagerState.graphManager.buildGraph(
|
|
1133
|
+
graphManagerState.graph,
|
|
1134
|
+
entities as unknown as Entity[],
|
|
1135
|
+
graphManagerState.graphBuildState,
|
|
1136
|
+
);
|
|
1137
|
+
|
|
1138
|
+
const dataProduct = graphManagerState.graph.getDataProduct(dataProductPath);
|
|
1139
|
+
const nativeAccess = guaranteeNonNullable(
|
|
1140
|
+
dataProduct.nativeModelAccess,
|
|
1141
|
+
`Data product '${dataProductPath}' has no native model access`,
|
|
1142
|
+
);
|
|
1143
|
+
const executionState = guaranteeNonNullable(
|
|
1144
|
+
nativeAccess.nativeModelExecutionContexts.find(
|
|
1145
|
+
(ctx) => ctx.key === executionKey,
|
|
1146
|
+
),
|
|
1147
|
+
`Can't find native execution context '${executionKey}'`,
|
|
1148
|
+
);
|
|
1149
|
+
|
|
1150
|
+
createSpy(
|
|
1151
|
+
MOCK__editorStore.depotServerClient,
|
|
1152
|
+
'getProject',
|
|
1153
|
+
).mockResolvedValue(projectData);
|
|
1154
|
+
createSpy(
|
|
1155
|
+
MOCK__editorStore.depotServerClient,
|
|
1156
|
+
'getEntities',
|
|
1157
|
+
).mockResolvedValue(entities);
|
|
1158
|
+
createSpy(
|
|
1159
|
+
MOCK__editorStore.depotServerClient,
|
|
1160
|
+
'getEntitiesByClassifier',
|
|
1161
|
+
).mockResolvedValue([]);
|
|
1162
|
+
createSpy(
|
|
1163
|
+
MOCK__editorStore.depotServerClient,
|
|
1164
|
+
'getEntitiesSummaryByClassifier',
|
|
1165
|
+
).mockResolvedValue([]);
|
|
1166
|
+
createSpy(
|
|
1167
|
+
MOCK__editorStore.depotServerClient,
|
|
1168
|
+
'getVersions',
|
|
1169
|
+
).mockResolvedValue([projectData.latestVersion]);
|
|
1170
|
+
createSpy(
|
|
1171
|
+
graphManagerState.graphManager,
|
|
1172
|
+
'pureCodeToLambda',
|
|
1173
|
+
).mockResolvedValue(new RawLambda(lambda.parameters, lambda.body));
|
|
1174
|
+
createSpy(
|
|
1175
|
+
graphManagerState.graphManager,
|
|
1176
|
+
'analyzeMappingModelCoverage',
|
|
1177
|
+
).mockResolvedValue(
|
|
1178
|
+
graphManagerState.graphManager.buildMappingModelCoverageAnalysisResult(
|
|
1179
|
+
{ mappedEntities: [] },
|
|
1180
|
+
executionState.mapping.value,
|
|
1181
|
+
),
|
|
1182
|
+
);
|
|
1183
|
+
|
|
1184
|
+
const mockQueryBuilderState = new LegendQueryDataProductQueryBuilderState(
|
|
1185
|
+
MOCK__editorStore.applicationStore,
|
|
1186
|
+
graphManagerState,
|
|
1187
|
+
QueryBuilderDataBrowserWorkflow.INSTANCE,
|
|
1188
|
+
new QueryBuilderActionConfig_QueryApplication(MOCK__editorStore),
|
|
1189
|
+
dataProduct,
|
|
1190
|
+
artifact,
|
|
1191
|
+
executionState,
|
|
1192
|
+
MOCK__editorStore.depotServerClient,
|
|
1193
|
+
{
|
|
1194
|
+
groupId: MOCK__editorStore.groupId,
|
|
1195
|
+
artifactId: MOCK__editorStore.artifactId,
|
|
1196
|
+
versionId: MOCK__editorStore.versionId,
|
|
1197
|
+
},
|
|
1198
|
+
async () => {
|
|
1199
|
+
/* no-op for tests */
|
|
1200
|
+
},
|
|
1201
|
+
async () => {
|
|
1202
|
+
throw new Error('Not implemented in tests');
|
|
1203
|
+
},
|
|
1204
|
+
new DataProductSelectorState(
|
|
1205
|
+
MOCK__editorStore.depotServerClient,
|
|
1206
|
+
MOCK__editorStore.applicationStore,
|
|
1207
|
+
),
|
|
1208
|
+
undefined,
|
|
1209
|
+
undefined,
|
|
1210
|
+
MOCK__editorStore.applicationStore.config.options.queryBuilderConfig,
|
|
1211
|
+
{
|
|
1212
|
+
groupId: MOCK__editorStore.groupId,
|
|
1213
|
+
artifactId: MOCK__editorStore.artifactId,
|
|
1214
|
+
versionId: MOCK__editorStore.versionId,
|
|
1215
|
+
dataProduct: dataProductPath,
|
|
1216
|
+
},
|
|
1217
|
+
);
|
|
1218
|
+
mockQueryBuilderState.initWithDataProduct(
|
|
1219
|
+
dataProduct,
|
|
1220
|
+
undefined,
|
|
1221
|
+
executionState,
|
|
1222
|
+
);
|
|
1223
|
+
|
|
1224
|
+
MOCK__editorStore.buildGraph = createMock();
|
|
1225
|
+
MOCK__editorStore.fetchDataProductArtifact = createMock();
|
|
1226
|
+
(
|
|
1227
|
+
MOCK__editorStore.fetchDataProductArtifact as ReturnType<typeof createMock>
|
|
1228
|
+
).mockResolvedValue(artifact);
|
|
1229
|
+
MOCK__editorStore.buildDataProductQueryBuilderState = createMock();
|
|
1230
|
+
(
|
|
1231
|
+
MOCK__editorStore.buildDataProductQueryBuilderState as ReturnType<
|
|
1232
|
+
typeof createMock
|
|
1233
|
+
>
|
|
1234
|
+
).mockResolvedValue(mockQueryBuilderState);
|
|
1235
|
+
graphManagerState.graphManager.initialize = createMock();
|
|
1236
|
+
|
|
1237
|
+
const sampleQueryRoute = generateDataProductSampleQueryRoute(
|
|
1238
|
+
MOCK__editorStore.groupId,
|
|
1239
|
+
MOCK__editorStore.artifactId,
|
|
1240
|
+
MOCK__editorStore.versionId,
|
|
1241
|
+
dataProductPath,
|
|
1242
|
+
MOCK__editorStore.templateQueryId,
|
|
1243
|
+
);
|
|
1244
|
+
|
|
1245
|
+
const renderResult = render(
|
|
1246
|
+
<ApplicationStoreProvider store={MOCK__editorStore.applicationStore}>
|
|
1247
|
+
<TEST__BrowserEnvironmentProvider initialEntries={[sampleQueryRoute]}>
|
|
1248
|
+
<LegendQueryFrameworkProvider>
|
|
1249
|
+
<Routes>
|
|
1250
|
+
<Route
|
|
1251
|
+
path={LEGEND_QUERY_ROUTE_PATTERN.DATA_PRODUCT_SAMPLE_QUERY}
|
|
1252
|
+
element={<DataProductSampleQueryCreator />}
|
|
1253
|
+
/>
|
|
1254
|
+
</Routes>
|
|
1255
|
+
</LegendQueryFrameworkProvider>
|
|
1256
|
+
</TEST__BrowserEnvironmentProvider>
|
|
1257
|
+
</ApplicationStoreProvider>,
|
|
1258
|
+
);
|
|
1259
|
+
await waitFor(() =>
|
|
1260
|
+
renderResult.getByTestId(QUERY_BUILDER_TEST_ID.QUERY_BUILDER),
|
|
1261
|
+
);
|
|
1262
|
+
|
|
1263
|
+
return {
|
|
1264
|
+
renderResult,
|
|
1265
|
+
queryBuilderState: guaranteeNonNullable(
|
|
1266
|
+
MOCK__editorStore.queryBuilderState,
|
|
1267
|
+
`Query builder state should have been initialized`,
|
|
1268
|
+
),
|
|
1269
|
+
};
|
|
1270
|
+
};
|
|
@@ -211,17 +211,19 @@ export const QueryEditorDataProductInfoModal = observer(
|
|
|
211
211
|
</div>
|
|
212
212
|
</div>
|
|
213
213
|
)}
|
|
214
|
-
|
|
215
|
-
<div className="dataspace-info-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
214
|
+
{mapping && (
|
|
215
|
+
<div className="dataspace-info-modal__field">
|
|
216
|
+
<div className="dataspace-info-modal__field__label">
|
|
217
|
+
Mapping
|
|
218
|
+
</div>
|
|
219
|
+
<div
|
|
220
|
+
className="dataspace-info-modal__field__value dataspace-info-modal__field__value--linkable"
|
|
221
|
+
onClick={() => flowResult(visitElement(mapping.path))}
|
|
222
|
+
>
|
|
223
|
+
{mapping.name}
|
|
224
|
+
</div>
|
|
223
225
|
</div>
|
|
224
|
-
|
|
226
|
+
)}
|
|
225
227
|
{selectedRuntime &&
|
|
226
228
|
selectedRuntime.runtimeValue instanceof LakehouseRuntime && (
|
|
227
229
|
<>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026-present, Goldman Sachs
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { observer, useLocalObservable } from 'mobx-react-lite';
|
|
18
|
+
import { useParams } from '@finos/legend-application/browser';
|
|
19
|
+
import { parseGAVCoordinates } from '@finos/legend-storage';
|
|
20
|
+
import {
|
|
21
|
+
useLegendQueryApplicationStore,
|
|
22
|
+
useLegendQueryBaseStore,
|
|
23
|
+
} from '../LegendQueryFrameworkProvider.js';
|
|
24
|
+
import { DataProductSampleQueryCreatorStore } from '../../stores/data-product/DataProductSampleQueryCreatorStore.js';
|
|
25
|
+
import { QueryEditorStoreContext } from '../QueryEditorStoreProvider.js';
|
|
26
|
+
import {
|
|
27
|
+
DATA_PRODUCT_SAMPLE_QUERY_CREATOR_ROUTE_PATTERN_TOKEN,
|
|
28
|
+
generateDataProductSampleQueryRoute,
|
|
29
|
+
type DataProductSampleQueryPathParams,
|
|
30
|
+
} from '../../__lib__/LegendQueryNavigation.js';
|
|
31
|
+
import { QueryEditor } from '../QueryEditor.js';
|
|
32
|
+
import { guaranteeNonNullable } from '@finos/legend-shared';
|
|
33
|
+
import { useApplicationStore } from '@finos/legend-application';
|
|
34
|
+
import { extractQueryParams } from '../utils/QueryParameterUtils.js';
|
|
35
|
+
import { useEffect } from 'react';
|
|
36
|
+
|
|
37
|
+
const DataProductSampleQueryCreatorStoreProvider: React.FC<{
|
|
38
|
+
children: React.ReactNode;
|
|
39
|
+
gav: string;
|
|
40
|
+
dataProductPath: string;
|
|
41
|
+
sampleQueryId: string;
|
|
42
|
+
params: Record<string, string> | undefined;
|
|
43
|
+
}> = ({ children, gav, dataProductPath, sampleQueryId, params }) => {
|
|
44
|
+
const { groupId, artifactId, versionId } = parseGAVCoordinates(gav);
|
|
45
|
+
const applicationStore = useLegendQueryApplicationStore();
|
|
46
|
+
const baseStore = useLegendQueryBaseStore();
|
|
47
|
+
const store = useLocalObservable(
|
|
48
|
+
() =>
|
|
49
|
+
new DataProductSampleQueryCreatorStore(
|
|
50
|
+
applicationStore,
|
|
51
|
+
baseStore.depotServerClient,
|
|
52
|
+
groupId,
|
|
53
|
+
artifactId,
|
|
54
|
+
versionId,
|
|
55
|
+
dataProductPath,
|
|
56
|
+
sampleQueryId,
|
|
57
|
+
params,
|
|
58
|
+
),
|
|
59
|
+
);
|
|
60
|
+
return (
|
|
61
|
+
<QueryEditorStoreContext.Provider value={store}>
|
|
62
|
+
{children}
|
|
63
|
+
</QueryEditorStoreContext.Provider>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const DataProductSampleQueryCreator = observer(() => {
|
|
68
|
+
const applicationStore = useApplicationStore();
|
|
69
|
+
const parameters = useParams<DataProductSampleQueryPathParams>();
|
|
70
|
+
const gav = guaranteeNonNullable(
|
|
71
|
+
parameters[DATA_PRODUCT_SAMPLE_QUERY_CREATOR_ROUTE_PATTERN_TOKEN.GAV],
|
|
72
|
+
);
|
|
73
|
+
const dataProductPath = guaranteeNonNullable(
|
|
74
|
+
parameters[
|
|
75
|
+
DATA_PRODUCT_SAMPLE_QUERY_CREATOR_ROUTE_PATTERN_TOKEN.DATA_PRODUCT_PATH
|
|
76
|
+
],
|
|
77
|
+
);
|
|
78
|
+
const sampleQueryId = guaranteeNonNullable(
|
|
79
|
+
parameters[
|
|
80
|
+
DATA_PRODUCT_SAMPLE_QUERY_CREATOR_ROUTE_PATTERN_TOKEN.SAMPLE_QUERY_ID
|
|
81
|
+
],
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const queryParams =
|
|
85
|
+
applicationStore.navigationService.navigator.getCurrentLocationParameters();
|
|
86
|
+
const processed = extractQueryParams(queryParams);
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
// clear params from URL after extracting
|
|
90
|
+
if (processed && Object.keys(processed).length) {
|
|
91
|
+
const { groupId, artifactId, versionId } = parseGAVCoordinates(gav);
|
|
92
|
+
applicationStore.navigationService.navigator.updateCurrentLocation(
|
|
93
|
+
generateDataProductSampleQueryRoute(
|
|
94
|
+
groupId,
|
|
95
|
+
artifactId,
|
|
96
|
+
versionId,
|
|
97
|
+
dataProductPath,
|
|
98
|
+
sampleQueryId,
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}, [applicationStore, gav, dataProductPath, sampleQueryId, processed]);
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<DataProductSampleQueryCreatorStoreProvider
|
|
106
|
+
gav={gav}
|
|
107
|
+
dataProductPath={dataProductPath}
|
|
108
|
+
sampleQueryId={sampleQueryId}
|
|
109
|
+
params={processed}
|
|
110
|
+
>
|
|
111
|
+
<QueryEditor />
|
|
112
|
+
</DataProductSampleQueryCreatorStoreProvider>
|
|
113
|
+
);
|
|
114
|
+
});
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026-present, Goldman Sachs
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
PanelHeader,
|
|
19
|
+
BasePopover,
|
|
20
|
+
ClickAwayListener,
|
|
21
|
+
ShareIcon,
|
|
22
|
+
TagIcon,
|
|
23
|
+
} from '@finos/legend-art';
|
|
24
|
+
import { observer } from 'mobx-react-lite';
|
|
25
|
+
import { useRef, useState } from 'react';
|
|
26
|
+
import {
|
|
27
|
+
ActionAlertActionType,
|
|
28
|
+
ActionAlertType,
|
|
29
|
+
useApplicationStore,
|
|
30
|
+
} from '@finos/legend-application';
|
|
31
|
+
import type { V1_SampleQuery } from '@finos/legend-graph';
|
|
32
|
+
import { flowResult } from 'mobx';
|
|
33
|
+
import type { LegendQueryDataProductQueryBuilderState } from '../../stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js';
|
|
34
|
+
import { generateDataProductSampleQueryRoute } from '../../__lib__/LegendQueryNavigation.js';
|
|
35
|
+
|
|
36
|
+
const DataProductSampleQueryDialog = observer(
|
|
37
|
+
(props: {
|
|
38
|
+
triggerElement: HTMLElement | null;
|
|
39
|
+
queryBuilderState: LegendQueryDataProductQueryBuilderState;
|
|
40
|
+
sampleQueries: V1_SampleQuery[];
|
|
41
|
+
onClose: () => void;
|
|
42
|
+
}) => {
|
|
43
|
+
const { triggerElement, queryBuilderState, sampleQueries, onClose } = props;
|
|
44
|
+
const applicationStore = useApplicationStore();
|
|
45
|
+
|
|
46
|
+
const loadSampleQuery = async (
|
|
47
|
+
sampleQuery: V1_SampleQuery,
|
|
48
|
+
): Promise<void> => {
|
|
49
|
+
const query =
|
|
50
|
+
await queryBuilderState.graphManagerState.graphManager.pureCodeToLambda(
|
|
51
|
+
sampleQuery.info.query,
|
|
52
|
+
);
|
|
53
|
+
queryBuilderState.initializeWithQuery(query);
|
|
54
|
+
onClose();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const loadQuery = async (sampleQuery: V1_SampleQuery): Promise<void> => {
|
|
58
|
+
if (queryBuilderState.changeDetectionState.hasChanged) {
|
|
59
|
+
applicationStore.alertService.setActionAlertInfo({
|
|
60
|
+
message:
|
|
61
|
+
'Unsaved changes will be lost if you continue. Do you still want to proceed?',
|
|
62
|
+
type: ActionAlertType.CAUTION,
|
|
63
|
+
actions: [
|
|
64
|
+
{
|
|
65
|
+
label: 'Proceed',
|
|
66
|
+
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
|
|
67
|
+
handler: (): void => {
|
|
68
|
+
flowResult(loadSampleQuery(sampleQuery));
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
label: 'Abort',
|
|
73
|
+
type: ActionAlertActionType.PROCEED,
|
|
74
|
+
default: true,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
});
|
|
78
|
+
} else {
|
|
79
|
+
flowResult(loadSampleQuery(sampleQuery));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const visitSampleQuery = (sampleQuery: V1_SampleQuery): void => {
|
|
84
|
+
const id = sampleQuery.info.id;
|
|
85
|
+
if (!id) {
|
|
86
|
+
applicationStore.notificationService.notifyWarning(
|
|
87
|
+
'Sample query does not have an ID and cannot be visited via URL',
|
|
88
|
+
);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const project = queryBuilderState.project;
|
|
92
|
+
applicationStore.navigationService.navigator.visitAddress(
|
|
93
|
+
applicationStore.navigationService.navigator.generateAddress(
|
|
94
|
+
generateDataProductSampleQueryRoute(
|
|
95
|
+
project.groupId,
|
|
96
|
+
project.artifactId,
|
|
97
|
+
project.versionId,
|
|
98
|
+
queryBuilderState.dataProduct.path,
|
|
99
|
+
id,
|
|
100
|
+
),
|
|
101
|
+
),
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<ClickAwayListener onClickAway={onClose}>
|
|
107
|
+
<div>
|
|
108
|
+
<BasePopover
|
|
109
|
+
open={true}
|
|
110
|
+
slotProps={{
|
|
111
|
+
paper: {
|
|
112
|
+
classes: {
|
|
113
|
+
root: '"query-builder__data-space__template-query-panel__container__root',
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
}}
|
|
117
|
+
className="query-builder__data-space__template-query-panel__container"
|
|
118
|
+
onClose={onClose}
|
|
119
|
+
anchorEl={triggerElement}
|
|
120
|
+
anchorOrigin={{
|
|
121
|
+
vertical: 'bottom',
|
|
122
|
+
horizontal: 'left',
|
|
123
|
+
}}
|
|
124
|
+
transformOrigin={{
|
|
125
|
+
vertical: 'top',
|
|
126
|
+
horizontal: 'center',
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<div className="query-builder__data-space__template-query-panel">
|
|
130
|
+
<div className="query-builder__data-space__template-query-panel__header">
|
|
131
|
+
Sample Queries
|
|
132
|
+
</div>
|
|
133
|
+
{sampleQueries.map((sampleQuery) => (
|
|
134
|
+
<div
|
|
135
|
+
key={sampleQuery.info.id ?? sampleQuery.title}
|
|
136
|
+
className="query-builder__data-space__template-query-panel__query"
|
|
137
|
+
>
|
|
138
|
+
<TagIcon className="query-builder__data-space__template-query-panel__query__icon" />
|
|
139
|
+
<button
|
|
140
|
+
className="query-builder__data-space__template-query-panel__query__entry"
|
|
141
|
+
title="click to load sample query"
|
|
142
|
+
onClick={() => {
|
|
143
|
+
flowResult(loadQuery(sampleQuery));
|
|
144
|
+
}}
|
|
145
|
+
>
|
|
146
|
+
<div className="query-builder__data-space__template-query-panel__query__entry__content">
|
|
147
|
+
<div className="query-builder__data-space__template-query-panel__query__entry__content__title">
|
|
148
|
+
{sampleQuery.title}
|
|
149
|
+
</div>
|
|
150
|
+
{sampleQuery.description && (
|
|
151
|
+
<div className="query-builder__data-space__template-query-panel__query__entry__content__description">
|
|
152
|
+
{sampleQuery.description}
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
</div>
|
|
156
|
+
</button>
|
|
157
|
+
<button
|
|
158
|
+
className="query-builder__data-space__template-query-panel__query__share"
|
|
159
|
+
title="Visit..."
|
|
160
|
+
disabled={!sampleQuery.info.id}
|
|
161
|
+
onClick={() => visitSampleQuery(sampleQuery)}
|
|
162
|
+
>
|
|
163
|
+
<ShareIcon />
|
|
164
|
+
<div className="query-builder__data-space__template-query-panel__query__share__label">
|
|
165
|
+
Visit
|
|
166
|
+
</div>
|
|
167
|
+
</button>
|
|
168
|
+
</div>
|
|
169
|
+
))}
|
|
170
|
+
</div>
|
|
171
|
+
</BasePopover>
|
|
172
|
+
</div>
|
|
173
|
+
</ClickAwayListener>
|
|
174
|
+
);
|
|
175
|
+
},
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
export const DataProductSampleQueryPanel = observer(
|
|
179
|
+
(props: { queryBuilderState: LegendQueryDataProductQueryBuilderState }) => {
|
|
180
|
+
const { queryBuilderState } = props;
|
|
181
|
+
const templateQueryButtonRef = useRef<HTMLButtonElement>(null);
|
|
182
|
+
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
183
|
+
|
|
184
|
+
const sampleQueries = queryBuilderState.isNativeMode
|
|
185
|
+
? (queryBuilderState.dataProductArtifact?.nativeModelAccess
|
|
186
|
+
?.sampleQueries ?? [])
|
|
187
|
+
: [];
|
|
188
|
+
|
|
189
|
+
if (sampleQueries.length === 0) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<PanelHeader className="query-builder__data-space__template-query">
|
|
195
|
+
<button
|
|
196
|
+
className="query-builder__data-space__template-query__btn"
|
|
197
|
+
ref={templateQueryButtonRef}
|
|
198
|
+
onClick={() => setIsDialogOpen(true)}
|
|
199
|
+
>
|
|
200
|
+
Sample Queries ( {sampleQueries.length} )
|
|
201
|
+
</button>
|
|
202
|
+
{isDialogOpen && (
|
|
203
|
+
<DataProductSampleQueryDialog
|
|
204
|
+
triggerElement={templateQueryButtonRef.current}
|
|
205
|
+
queryBuilderState={queryBuilderState}
|
|
206
|
+
sampleQueries={sampleQueries}
|
|
207
|
+
onClose={() => setIsDialogOpen(false)}
|
|
208
|
+
/>
|
|
209
|
+
)}
|
|
210
|
+
</PanelHeader>
|
|
211
|
+
);
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
export const renderDataProductSampleQueryPanelContent = (
|
|
216
|
+
queryBuilderState: LegendQueryDataProductQueryBuilderState,
|
|
217
|
+
): React.ReactNode => (
|
|
218
|
+
<DataProductSampleQueryPanel queryBuilderState={queryBuilderState} />
|
|
219
|
+
);
|