@finos/legend-application-query 13.8.8 → 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 +91 -5
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.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 +42 -30
- 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 -0
- 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 +227 -3
- 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 +60 -46
- package/src/stores/data-product/DataProductSampleQueryCreatorStore.ts +135 -0
- package/src/stores/data-product/query-builder/DataProductArtifactHelper.ts +13 -0
- 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',
|
|
@@ -845,6 +853,7 @@ export const TEST__setUpDataProductNativeExistingQueryEditor = async (
|
|
|
845
853
|
executionKey: string,
|
|
846
854
|
lambda: RawLambda,
|
|
847
855
|
entities: PlainObject<Entity>[],
|
|
856
|
+
artifact?: V1_DataProductArtifact | undefined,
|
|
848
857
|
): Promise<{
|
|
849
858
|
renderResult: RenderResult;
|
|
850
859
|
queryBuilderState: QueryBuilderState;
|
|
@@ -974,20 +983,22 @@ export const TEST__setUpDataProductNativeExistingQueryEditor = async (
|
|
|
974
983
|
QueryBuilderDataBrowserWorkflow.INSTANCE,
|
|
975
984
|
new QueryBuilderActionConfig_QueryApplication(MOCK__editorStore),
|
|
976
985
|
dataProduct,
|
|
977
|
-
|
|
986
|
+
artifact,
|
|
978
987
|
executionState,
|
|
979
988
|
MOCK__editorStore.depotServerClient,
|
|
980
989
|
{ groupId: 'test.group', artifactId: 'test-artifact', versionId: '0.0.0' },
|
|
981
990
|
async () => {
|
|
982
991
|
/* no-op for tests */
|
|
983
992
|
},
|
|
993
|
+
async () => {
|
|
994
|
+
throw new Error('Not implemented in tests');
|
|
995
|
+
},
|
|
984
996
|
new DataProductSelectorState(
|
|
985
997
|
MOCK__editorStore.depotServerClient,
|
|
986
998
|
MOCK__editorStore.applicationStore,
|
|
987
999
|
),
|
|
988
1000
|
undefined,
|
|
989
1001
|
undefined,
|
|
990
|
-
undefined,
|
|
991
1002
|
MOCK__editorStore.applicationStore.config.options.queryBuilderConfig,
|
|
992
1003
|
{
|
|
993
1004
|
groupId: 'test.group',
|
|
@@ -1044,3 +1055,216 @@ export const TEST__setUpDataProductNativeExistingQueryEditor = async (
|
|
|
1044
1055
|
),
|
|
1045
1056
|
};
|
|
1046
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
|
+
};
|
|
@@ -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
|
+
);
|