@finos/legend-application-query 13.7.205 → 13.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/lib/__lib__/LegendQueryNavigation.d.ts +16 -10
  2. package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
  3. package/lib/__lib__/LegendQueryNavigation.js +17 -12
  4. package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
  5. package/lib/__lib__/LegendQueryUserDataHelper.d.ts +25 -7
  6. package/lib/__lib__/LegendQueryUserDataHelper.d.ts.map +1 -1
  7. package/lib/__lib__/LegendQueryUserDataHelper.js +81 -6
  8. package/lib/__lib__/LegendQueryUserDataHelper.js.map +1 -1
  9. package/lib/__lib__/LegendQueryUserDataSpaceHelper.d.ts +21 -4
  10. package/lib/__lib__/LegendQueryUserDataSpaceHelper.d.ts.map +1 -1
  11. package/lib/__lib__/LegendQueryUserDataSpaceHelper.js +17 -0
  12. package/lib/__lib__/LegendQueryUserDataSpaceHelper.js.map +1 -1
  13. package/lib/application/LegendQueryApplicationConfig.d.ts +10 -0
  14. package/lib/application/LegendQueryApplicationConfig.d.ts.map +1 -1
  15. package/lib/application/LegendQueryApplicationConfig.js +16 -0
  16. package/lib/application/LegendQueryApplicationConfig.js.map +1 -1
  17. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
  18. package/lib/components/Core_LegendQueryApplicationPlugin.js +7 -3
  19. package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
  20. package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
  21. package/lib/components/LegendQueryWebApplication.js +2 -2
  22. package/lib/components/LegendQueryWebApplication.js.map +1 -1
  23. package/lib/components/QueryEditor.d.ts.map +1 -1
  24. package/lib/components/QueryEditor.js +5 -2
  25. package/lib/components/QueryEditor.js.map +1 -1
  26. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts +8 -0
  27. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts.map +1 -1
  28. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js +190 -8
  29. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js.map +1 -1
  30. package/lib/components/data-product/DataProductInfo.d.ts +28 -0
  31. package/lib/components/data-product/DataProductInfo.d.ts.map +1 -0
  32. package/lib/components/data-product/DataProductInfo.js +89 -0
  33. package/lib/components/data-product/DataProductInfo.js.map +1 -0
  34. package/lib/components/{data-space/DataSpaceQueryCreator.d.ts → data-product/LegendQueryDataProductQueryBuilder.d.ts} +3 -4
  35. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.d.ts.map +1 -0
  36. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js +98 -0
  37. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js.map +1 -0
  38. package/lib/components/data-space/DataProductQueryCreator.d.ts +36 -0
  39. package/lib/components/data-space/DataProductQueryCreator.d.ts.map +1 -0
  40. package/lib/components/data-space/DataProductQueryCreator.js +76 -0
  41. package/lib/components/data-space/DataProductQueryCreator.js.map +1 -0
  42. package/lib/index.css +1 -1
  43. package/lib/index.d.ts +1 -1
  44. package/lib/index.d.ts.map +1 -1
  45. package/lib/index.js +1 -1
  46. package/lib/index.js.map +1 -1
  47. package/lib/light-mode.css +1 -1
  48. package/lib/package.json +2 -1
  49. package/lib/stores/QueryEditorStore.d.ts +46 -2
  50. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  51. package/lib/stores/QueryEditorStore.js +251 -5
  52. package/lib/stores/QueryEditorStore.js.map +1 -1
  53. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.d.ts +21 -0
  54. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.d.ts.map +1 -0
  55. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js +35 -0
  56. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js.map +1 -0
  57. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts +11 -3
  58. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts.map +1 -1
  59. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js +50 -8
  60. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js.map +1 -1
  61. package/lib/stores/data-space/DataProductQueryCreatorStore.d.ts +94 -0
  62. package/lib/stores/data-space/DataProductQueryCreatorStore.d.ts.map +1 -0
  63. package/lib/stores/data-space/DataProductQueryCreatorStore.js +388 -0
  64. package/lib/stores/data-space/DataProductQueryCreatorStore.js.map +1 -0
  65. package/lib/stores/data-space/DataProductSelectorState.d.ts +44 -0
  66. package/lib/stores/data-space/DataProductSelectorState.d.ts.map +1 -0
  67. package/lib/stores/data-space/DataProductSelectorState.js +111 -0
  68. package/lib/stores/data-space/DataProductSelectorState.js.map +1 -0
  69. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts.map +1 -1
  70. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js +3 -0
  71. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js.map +1 -1
  72. package/lib/stores/data-space/LegendQueryBareQueryBuilderState.d.ts +1 -1
  73. package/lib/stores/data-space/LegendQueryBareQueryBuilderState.d.ts.map +1 -1
  74. package/lib/stores/data-space/LegendQueryBareQueryBuilderState.js +1 -1
  75. package/lib/stores/data-space/LegendQueryBareQueryBuilderState.js.map +1 -1
  76. package/lib/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.d.ts +4 -3
  77. package/lib/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.d.ts.map +1 -1
  78. package/lib/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.js +24 -29
  79. package/lib/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.js.map +1 -1
  80. package/package.json +8 -7
  81. package/src/__lib__/LegendQueryNavigation.ts +76 -18
  82. package/src/__lib__/LegendQueryUserDataHelper.ts +177 -12
  83. package/src/__lib__/LegendQueryUserDataSpaceHelper.ts +54 -4
  84. package/src/application/LegendQueryApplicationConfig.ts +31 -0
  85. package/src/components/Core_LegendQueryApplicationPlugin.tsx +8 -2
  86. package/src/components/LegendQueryWebApplication.tsx +8 -4
  87. package/src/components/QueryEditor.tsx +13 -0
  88. package/src/components/__test-utils__/QueryEditorComponentTestUtils.tsx +418 -5
  89. package/src/components/data-product/DataProductInfo.tsx +297 -0
  90. package/src/components/data-product/LegendQueryDataProductQueryBuilder.tsx +268 -0
  91. package/src/components/data-space/DataProductQueryCreator.tsx +167 -0
  92. package/src/components/data-space/DataSpaceQuerySetup.tsx +1 -1
  93. package/src/index.ts +6 -0
  94. package/src/stores/QueryEditorStore.ts +485 -2
  95. package/src/stores/data-product/query-builder/DataProductArtifactHelper.ts +48 -0
  96. package/src/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.ts +77 -16
  97. package/src/stores/data-space/DataProductQueryCreatorStore.ts +765 -0
  98. package/src/stores/data-space/DataProductSelectorState.ts +164 -0
  99. package/src/stores/data-space/DataSpaceTemplateQueryCreatorStore.ts +10 -0
  100. package/src/stores/data-space/LegendQueryBareQueryBuilderState.ts +1 -1
  101. package/src/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.ts +27 -54
  102. package/tsconfig.json +6 -2
  103. package/lib/components/data-space/DataSpaceQueryCreator.d.ts.map +0 -1
  104. package/lib/components/data-space/DataSpaceQueryCreator.js +0 -62
  105. package/lib/components/data-space/DataSpaceQueryCreator.js.map +0 -1
  106. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts +0 -92
  107. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts.map +0 -1
  108. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js +0 -400
  109. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js.map +0 -1
  110. package/src/components/data-space/DataSpaceQueryCreator.tsx +0 -119
  111. package/src/stores/data-space/DataSpaceQueryCreatorStore.ts +0 -697
@@ -0,0 +1,765 @@
1
+ /**
2
+ * Copyright (c) 2020-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
+ type Query,
19
+ type QuerySearchSpecification,
20
+ type RawLambda,
21
+ extractElementNameFromPath,
22
+ RuntimePointer,
23
+ PackageableElementExplicitReference,
24
+ QueryProjectCoordinates,
25
+ type DataProductAccessType,
26
+ type V1_DataProductArtifact,
27
+ } from '@finos/legend-graph';
28
+ import {
29
+ type DepotServerClient,
30
+ LATEST_VERSION_ALIAS,
31
+ } from '@finos/legend-server-depot';
32
+ import {
33
+ LogEvent,
34
+ assertErrorThrown,
35
+ assertNonNullable,
36
+ assertTrue,
37
+ guaranteeNonNullable,
38
+ returnUndefOnError,
39
+ uuid,
40
+ type GeneratorFn,
41
+ } from '@finos/legend-shared';
42
+ import {
43
+ QueryBuilderDataBrowserWorkflow,
44
+ type QueryBuilderState,
45
+ } from '@finos/legend-query-builder';
46
+ import {
47
+ parseGACoordinates,
48
+ type ProjectGAVCoordinates,
49
+ type DepotEntityWithOrigin,
50
+ } from '@finos/legend-storage';
51
+ import {
52
+ type DataSpaceExecutionContext,
53
+ getDataSpace,
54
+ } from '@finos/legend-extension-dsl-data-space/graph';
55
+ import {
56
+ QueryBuilderActionConfig_QueryApplication,
57
+ QueryEditorStore,
58
+ type QueryPersistConfiguration,
59
+ } from '../QueryEditorStore.js';
60
+ import type { LegendQueryApplicationStore } from '../LegendQueryBaseStore.js';
61
+ import {
62
+ type DataSpaceQueryBuilderState,
63
+ ResolvedDataSpaceEntityWithOrigin,
64
+ createQueryClassTaggedValue,
65
+ createQueryDataSpaceTaggedValue,
66
+ } from '@finos/legend-extension-dsl-data-space/application';
67
+ import { DataProductSelectorState } from './DataProductSelectorState.js';
68
+ import { LegendQueryUserDataHelper } from '../../__lib__/LegendQueryUserDataHelper.js';
69
+ import {
70
+ type VisitedLegacyDataProduct,
71
+ type VisitedDataProduct,
72
+ createVisitedDataSpaceId,
73
+ createVisitedDataProductId,
74
+ hasDataSpaceInfoBeenVisited,
75
+ createSimpleVisitedDataspace,
76
+ createSimpleVisitedDataProduct,
77
+ } from '../../__lib__/LegendQueryUserDataSpaceHelper.js';
78
+ import { LEGEND_QUERY_APP_EVENT } from '../../__lib__/LegendQueryEvent.js';
79
+ import {
80
+ action,
81
+ computed,
82
+ flow,
83
+ flowResult,
84
+ makeObservable,
85
+ observable,
86
+ } from 'mobx';
87
+ import { APPLICATION_EVENT } from '@finos/legend-application';
88
+ import { LegendQueryBareQueryBuilderState } from './LegendQueryBareQueryBuilderState.js';
89
+ import { LegendQueryDataSpaceQueryBuilderState } from './query-builder/LegendQueryDataSpaceQueryBuilderState.js';
90
+ import type { LegendQueryDataProductQueryBuilderState } from '../data-product/query-builder/LegendQueryDataProductQueryBuilderState.js';
91
+ import { resolveDefaultDataProductAccessType } from '../data-product/query-builder/DataProductArtifactHelper.js';
92
+
93
+ export abstract class LegendQueryableElement {
94
+ readonly groupId: string;
95
+ readonly artifactId: string;
96
+ readonly versionId: string;
97
+
98
+ constructor(groupId: string, artifactId: string, versionId: string) {
99
+ this.groupId = groupId;
100
+ this.artifactId = artifactId;
101
+ this.versionId = versionId;
102
+ }
103
+
104
+ abstract get path(): string;
105
+ abstract get execContext(): string;
106
+ }
107
+
108
+ // TODO:
109
+ // 1. handle route to data product
110
+ // 2. handle hyration
111
+ export class QueryableLegacyDataProduct extends LegendQueryableElement {
112
+ readonly dataSpacePath: string;
113
+ readonly executionContext: string;
114
+ readonly runtimePath?: string | undefined;
115
+ readonly classPath?: string | undefined;
116
+
117
+ constructor(
118
+ groupId: string,
119
+ artifactId: string,
120
+ versionId: string,
121
+ dataSpacePath: string,
122
+ executionContext: string,
123
+ runtimePath?: string | undefined,
124
+ classPath?: string | undefined,
125
+ ) {
126
+ super(groupId, artifactId, versionId);
127
+ this.dataSpacePath = dataSpacePath;
128
+ this.executionContext = executionContext;
129
+ this.runtimePath = runtimePath;
130
+ this.classPath = classPath;
131
+ }
132
+
133
+ get path(): string {
134
+ return this.dataSpacePath;
135
+ }
136
+
137
+ get execContext(): string {
138
+ return this.executionContext;
139
+ }
140
+ }
141
+
142
+ export class QueryableDataProduct extends LegendQueryableElement {
143
+ readonly dataProductPath: string;
144
+ readonly dataProductType: string;
145
+ readonly id: string;
146
+
147
+ constructor(
148
+ groupId: string,
149
+ artifactId: string,
150
+ versionId: string,
151
+ dataProductPath: string,
152
+ dataProductType: string,
153
+ id: string,
154
+ ) {
155
+ super(groupId, artifactId, versionId);
156
+ this.dataProductPath = dataProductPath;
157
+ this.dataProductType = dataProductType;
158
+ this.id = id;
159
+ }
160
+
161
+ get path(): string {
162
+ return this.dataProductPath;
163
+ }
164
+
165
+ get execContext(): string {
166
+ return this.id;
167
+ }
168
+ }
169
+
170
+ const enum VisitedEntityType {
171
+ DATASPACE = 'DATASPACE',
172
+ DATAPRODUCT = 'DATAPRODUCT',
173
+ }
174
+
175
+ export class DataProductQueryCreatorStore extends QueryEditorStore {
176
+ queryableElement: LegendQueryableElement | undefined;
177
+ productSelectorState: DataProductSelectorState;
178
+ declare queryBuilderState:
179
+ | DataSpaceQueryBuilderState
180
+ | LegendQueryDataProductQueryBuilderState
181
+ | LegendQueryBareQueryBuilderState
182
+ | undefined;
183
+
184
+ constructor(
185
+ applicationStore: LegendQueryApplicationStore,
186
+ depotServerClient: DepotServerClient,
187
+ queryableElement: LegendQueryableElement | undefined,
188
+ ) {
189
+ super(applicationStore, depotServerClient);
190
+ makeObservable(this, {
191
+ changeDataSpace: flow,
192
+ changeDataProduct: flow,
193
+ productSelectorState: observable,
194
+ queryableElement: observable,
195
+ setQueryableElement: action,
196
+ canPersistToSavedQuery: computed,
197
+ });
198
+ this.queryableElement = queryableElement;
199
+ this.productSelectorState = new DataProductSelectorState(
200
+ depotServerClient,
201
+ applicationStore,
202
+ );
203
+ }
204
+
205
+ override get canPersistToSavedQuery(): boolean {
206
+ return Boolean(this.queryableElement);
207
+ }
208
+
209
+ override get isViewProjectActionDisabled(): boolean {
210
+ return !this.queryableElement;
211
+ }
212
+
213
+ getProjectInfo(): ProjectGAVCoordinates | undefined {
214
+ return this.queryableElement;
215
+ }
216
+
217
+ setQueryableElement(val: LegendQueryableElement | undefined): void {
218
+ this.queryableElement = val;
219
+ }
220
+
221
+ reConfigureWithDataSpaceInfo(
222
+ info: ResolvedDataSpaceEntityWithOrigin,
223
+ ): boolean {
224
+ if (info.origin && info.defaultExecutionContext) {
225
+ this.queryableElement = new QueryableLegacyDataProduct(
226
+ info.origin.groupId,
227
+ info.origin.artifactId,
228
+ LATEST_VERSION_ALIAS,
229
+ info.path,
230
+ info.defaultExecutionContext,
231
+ );
232
+ return true;
233
+ }
234
+ return false;
235
+ }
236
+
237
+ reConfigureWithDataProductInfo(
238
+ info: DepotEntityWithOrigin,
239
+ artifact: V1_DataProductArtifact,
240
+ ): QueryableDataProduct | undefined {
241
+ if (info.origin) {
242
+ const resolved = resolveDefaultDataProductAccessType(artifact);
243
+ const queryableElement = new QueryableDataProduct(
244
+ info.origin.groupId,
245
+ info.origin.artifactId,
246
+ LATEST_VERSION_ALIAS,
247
+ info.path,
248
+ resolved.type,
249
+ resolved.id,
250
+ );
251
+ this.queryableElement = queryableElement;
252
+ return queryableElement;
253
+ }
254
+ return undefined;
255
+ }
256
+
257
+ override *initialize(): GeneratorFn<void> {
258
+ if (!this.queryableElement) {
259
+ const mostRecent = this.getMostRecentlyVisited();
260
+ if (mostRecent) {
261
+ if (mostRecent.type === VisitedEntityType.DATAPRODUCT) {
262
+ const visited = mostRecent.visited as VisitedDataProduct;
263
+ this.setQueryableElement(
264
+ new QueryableDataProduct(
265
+ visited.groupId,
266
+ visited.artifactId,
267
+ visited.versionId ?? LATEST_VERSION_ALIAS,
268
+ visited.path,
269
+ visited.dataProductAccessType ?? '',
270
+ visited.accessId ?? '',
271
+ ),
272
+ );
273
+ } else {
274
+ const visited = mostRecent.visited as VisitedLegacyDataProduct;
275
+ this.setQueryableElement(
276
+ new QueryableLegacyDataProduct(
277
+ visited.groupId,
278
+ visited.artifactId,
279
+ visited.versionId ?? LATEST_VERSION_ALIAS,
280
+ visited.path,
281
+ visited.execContext ?? '',
282
+ ),
283
+ );
284
+ }
285
+ }
286
+ }
287
+ // Kick off product loading so dropdown data is available for all flows
288
+ if (!this.productSelectorState.isCompletelyLoaded) {
289
+ flowResult(this.productSelectorState.loadProducts()).catch(
290
+ this.applicationStore.alertUnhandledError,
291
+ );
292
+ }
293
+ yield flowResult(super.initialize());
294
+ }
295
+
296
+ async initializeQueryBuilderState(): Promise<QueryBuilderState> {
297
+ if (this.queryableElement) {
298
+ if (this.queryableElement instanceof QueryableDataProduct) {
299
+ return this.initializeQueryBuilderStateWithDataProduct(
300
+ this.queryableElement,
301
+ undefined,
302
+ );
303
+ }
304
+ return this.initializeQueryBuilderStateWithQueryableDataSpace(
305
+ this.queryableElement as QueryableLegacyDataProduct,
306
+ );
307
+ } else {
308
+ const queryBuilderState = new LegendQueryBareQueryBuilderState(
309
+ this,
310
+ this.applicationStore,
311
+ this.graphManagerState,
312
+ this.depotServerClient,
313
+ {
314
+ onDataSpaceChange: (
315
+ dataSpaceInfo: ResolvedDataSpaceEntityWithOrigin,
316
+ ) => {
317
+ if (dataSpaceInfo.defaultExecutionContext) {
318
+ this.changeDataSpace(dataSpaceInfo);
319
+ } else {
320
+ this.applicationStore.notificationService.notifyWarning(
321
+ `Can't switch data product: default execution context not specified`,
322
+ );
323
+ }
324
+ },
325
+ onDataProductChange: (dataProductInfo: DepotEntityWithOrigin) => {
326
+ flowResult(this.changeDataProduct(dataProductInfo)).catch(
327
+ this.applicationStore.alertUnhandledError,
328
+ );
329
+ },
330
+ },
331
+ this.applicationStore.config.options.queryBuilderConfig,
332
+ this.productSelectorState,
333
+ );
334
+ return queryBuilderState;
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Returns the most recently visited entity (data product or data space)
340
+ * based on `lastViewedAt` timestamp. No network verification is performed;
341
+ * if the entity no longer exists, `onInitializeFailure()` will handle
342
+ * cleanup and fall back to the bare selector UI.
343
+ */
344
+ getMostRecentlyVisited():
345
+ | {
346
+ type: VisitedEntityType;
347
+ visited: VisitedLegacyDataProduct | VisitedDataProduct;
348
+ }
349
+ | undefined {
350
+ const visitedDataSpaces =
351
+ LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(
352
+ this.applicationStore.userDataService,
353
+ );
354
+ const visitedDataProducts =
355
+ LegendQueryUserDataHelper.getRecentlyVisitedDataProducts(
356
+ this.applicationStore.userDataService,
357
+ );
358
+
359
+ const allVisited: {
360
+ type: VisitedEntityType;
361
+ visited: VisitedLegacyDataProduct | VisitedDataProduct;
362
+ }[] = [
363
+ ...visitedDataSpaces.map((v) => ({
364
+ type: VisitedEntityType.DATASPACE as const,
365
+ visited: v,
366
+ })),
367
+ ...visitedDataProducts.map((v) => ({
368
+ type: VisitedEntityType.DATAPRODUCT as const,
369
+ visited: v,
370
+ })),
371
+ ].sort(
372
+ (a, b) => (b.visited.lastViewedAt ?? 0) - (a.visited.lastViewedAt ?? 0),
373
+ );
374
+
375
+ return allVisited[0];
376
+ }
377
+
378
+ async initializeQueryBuilderStateWithDataProduct(
379
+ queryableDataProduct: QueryableDataProduct,
380
+ _artifact: V1_DataProductArtifact | undefined,
381
+ ): Promise<QueryBuilderState> {
382
+ const artifact =
383
+ _artifact ??
384
+ (await this.fetchDataProductArtifact(
385
+ queryableDataProduct.groupId,
386
+ queryableDataProduct.artifactId,
387
+ queryableDataProduct.versionId,
388
+ queryableDataProduct.dataProductPath,
389
+ ));
390
+
391
+ const queryBuilderState = await this.buildDataProductQueryBuilderState(
392
+ queryableDataProduct.groupId,
393
+ queryableDataProduct.artifactId,
394
+ queryableDataProduct.versionId,
395
+ queryableDataProduct.dataProductPath,
396
+ artifact,
397
+ queryableDataProduct.id,
398
+ queryableDataProduct.dataProductType as DataProductAccessType,
399
+ async (dataProductInfo: DepotEntityWithOrigin) => {
400
+ if (dataProductInfo instanceof ResolvedDataSpaceEntityWithOrigin) {
401
+ flowResult(this.changeDataSpace(dataProductInfo)).catch(
402
+ this.applicationStore.alertUnhandledError,
403
+ );
404
+ } else {
405
+ flowResult(this.changeDataProduct(dataProductInfo)).catch(
406
+ this.applicationStore.alertUnhandledError,
407
+ );
408
+ }
409
+ },
410
+ this.productSelectorState,
411
+ );
412
+
413
+ // add to visited data products
414
+ this.addVisitedProduct(queryableDataProduct, artifact);
415
+
416
+ return queryBuilderState;
417
+ }
418
+
419
+ async initializeQueryBuilderStateWithQueryableDataSpace(
420
+ queryableDataSpace: QueryableLegacyDataProduct,
421
+ ): Promise<QueryBuilderState> {
422
+ const { dataSpaceAnalysisResult, isLightGraphEnabled } =
423
+ await this.buildGraphAndDataspaceAnalyticsResult(
424
+ queryableDataSpace.groupId,
425
+ queryableDataSpace.artifactId,
426
+ queryableDataSpace.versionId,
427
+ queryableDataSpace.executionContext,
428
+ queryableDataSpace.dataSpacePath,
429
+ );
430
+ const dataSpace = getDataSpace(
431
+ queryableDataSpace.dataSpacePath,
432
+ this.graphManagerState.graph,
433
+ );
434
+ const executionContext = guaranteeNonNullable(
435
+ dataSpace.executionContexts.find(
436
+ (context) => context.name === queryableDataSpace.executionContext,
437
+ ),
438
+ `Can't find execution context '${queryableDataSpace.executionContext}'`,
439
+ );
440
+ const sourceInfo = {
441
+ groupId: queryableDataSpace.groupId,
442
+ artifactId: queryableDataSpace.artifactId,
443
+ versionId: queryableDataSpace.versionId,
444
+ dataSpace: dataSpace.path,
445
+ };
446
+ const visitedDataSpaces =
447
+ LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(
448
+ this.applicationStore.userDataService,
449
+ );
450
+ const queryBuilderState = new LegendQueryDataSpaceQueryBuilderState(
451
+ this.applicationStore,
452
+ this.graphManagerState,
453
+ QueryBuilderDataBrowserWorkflow.INSTANCE,
454
+ new QueryBuilderActionConfig_QueryApplication(this),
455
+ dataSpace,
456
+ executionContext,
457
+ isLightGraphEnabled,
458
+ this.depotServerClient,
459
+ {
460
+ groupId: queryableDataSpace.groupId,
461
+ artifactId: queryableDataSpace.artifactId,
462
+ versionId: queryableDataSpace.versionId,
463
+ },
464
+ (dataSpaceInfo: ResolvedDataSpaceEntityWithOrigin) =>
465
+ hasDataSpaceInfoBeenVisited(dataSpaceInfo, visitedDataSpaces),
466
+ async (dataSpaceInfo: ResolvedDataSpaceEntityWithOrigin) => {
467
+ flowResult(this.changeDataSpace(dataSpaceInfo)).catch(
468
+ this.applicationStore.alertUnhandledError,
469
+ );
470
+ },
471
+ this.productSelectorState,
472
+ (dataProductInfo: DepotEntityWithOrigin) => {
473
+ flowResult(this.changeDataProduct(dataProductInfo)).catch(
474
+ this.applicationStore.alertUnhandledError,
475
+ );
476
+ },
477
+ dataSpaceAnalysisResult,
478
+ (ec: DataSpaceExecutionContext) => {
479
+ returnUndefOnError(() =>
480
+ LegendQueryUserDataHelper.updateVisitedDataSpaceExecContext(
481
+ this.applicationStore.userDataService,
482
+ queryableDataSpace.groupId,
483
+ queryableDataSpace.artifactId,
484
+ dataSpace.path,
485
+ ec.name,
486
+ ),
487
+ );
488
+ },
489
+ undefined,
490
+ undefined,
491
+ this.applicationStore.config.options.queryBuilderConfig,
492
+ sourceInfo,
493
+ ).withOptions(
494
+ this.productSelectorState.legacyDataProducts,
495
+ this.productSelectorState.dataProducts,
496
+ );
497
+ queryBuilderState.setExecutionContext(executionContext);
498
+ await queryBuilderState.propagateExecutionContextChange(true);
499
+
500
+ // set runtime if already chosen
501
+ if (queryableDataSpace.runtimePath) {
502
+ queryBuilderState.changeRuntime(
503
+ new RuntimePointer(
504
+ PackageableElementExplicitReference.create(
505
+ this.graphManagerState.graph.getRuntime(
506
+ queryableDataSpace.runtimePath,
507
+ ),
508
+ ),
509
+ ),
510
+ );
511
+ }
512
+
513
+ // set class if already chosen
514
+ if (queryableDataSpace.classPath) {
515
+ queryBuilderState.changeClass(
516
+ this.graphManagerState.graph.getClass(queryableDataSpace.classPath),
517
+ );
518
+ }
519
+
520
+ // add to visited dataspaces
521
+ this.addVisitedDataSpace(queryableDataSpace);
522
+ return queryBuilderState;
523
+ }
524
+
525
+ *changeDataSpace(val: ResolvedDataSpaceEntityWithOrigin): GeneratorFn<void> {
526
+ try {
527
+ assertTrue(
528
+ this.reConfigureWithDataSpaceInfo(val),
529
+ 'Data product selected does not contain valid inputs, groupId, artifactId, and version',
530
+ );
531
+ this.initState.inProgress();
532
+ this.graphManagerState.resetGraph();
533
+ yield flowResult(this.buildGraph());
534
+ this.queryBuilderState =
535
+ (yield this.initializeQueryBuilderState()) as DataSpaceQueryBuilderState;
536
+ this.queryLoaderState.initialize(this.queryBuilderState);
537
+ this.initState.pass();
538
+ } catch (error) {
539
+ assertErrorThrown(error);
540
+ this.applicationStore.notificationService.notify(
541
+ `Can't to change data product: ${error.message}`,
542
+ );
543
+ this.applicationStore.logService.error(
544
+ LogEvent.create(APPLICATION_EVENT.GENERIC_FAILURE),
545
+ error,
546
+ );
547
+ this.onInitializeFailure();
548
+ this.initState.fail();
549
+ }
550
+ }
551
+
552
+ *changeDataProduct(val: DepotEntityWithOrigin): GeneratorFn<void> {
553
+ try {
554
+ const origin = guaranteeNonNullable(
555
+ val.origin,
556
+ 'Missing origin information for selected data product',
557
+ );
558
+ const artifact = (yield this.fetchDataProductArtifact(
559
+ origin.groupId,
560
+ origin.artifactId,
561
+ origin.versionId,
562
+ val.path,
563
+ )) as V1_DataProductArtifact;
564
+ const queryableDataProduct = this.reConfigureWithDataProductInfo(
565
+ val,
566
+ artifact,
567
+ );
568
+ assertNonNullable(
569
+ queryableDataProduct,
570
+ 'Data product selected does not contain valid inputs, groupId, artifactId, and version',
571
+ );
572
+ this.initState.inProgress();
573
+ this.graphManagerState.resetGraph();
574
+ this.queryBuilderState =
575
+ (yield this.initializeQueryBuilderStateWithDataProduct(
576
+ queryableDataProduct,
577
+ artifact,
578
+ )) as LegendQueryDataProductQueryBuilderState;
579
+ this.queryLoaderState.initialize(this.queryBuilderState);
580
+ this.initState.pass();
581
+ } catch (error) {
582
+ assertErrorThrown(error);
583
+ this.applicationStore.notificationService.notify(
584
+ `Can't to change data product: ${error.message}`,
585
+ );
586
+ this.applicationStore.logService.error(
587
+ LogEvent.create(APPLICATION_EVENT.GENERIC_FAILURE),
588
+ error,
589
+ );
590
+ this.onInitializeFailure();
591
+ this.initState.fail();
592
+ }
593
+ }
594
+
595
+ override *buildGraph(): GeneratorFn<void> {
596
+ // do nothing
597
+ }
598
+
599
+ addVisitedProduct(
600
+ element: QueryableDataProduct,
601
+ artifact?: V1_DataProductArtifact | undefined,
602
+ ): void {
603
+ try {
604
+ LegendQueryUserDataHelper.addVisitedDataProduct(
605
+ this.applicationStore.userDataService,
606
+ createSimpleVisitedDataProduct(
607
+ element.groupId,
608
+ element.artifactId,
609
+ element.versionId,
610
+ element.path,
611
+ element.id,
612
+ element.dataProductType,
613
+ artifact?.dataProduct.title,
614
+ artifact?.dataProduct.description,
615
+ artifact?.dataProduct.deploymentId,
616
+ ),
617
+ );
618
+ } catch (error) {
619
+ assertErrorThrown(error);
620
+ this.applicationStore.logService.warn(
621
+ LogEvent.create(LEGEND_QUERY_APP_EVENT.LOCAL_STORAGE_PERSIST_ERROR),
622
+ error.message,
623
+ );
624
+ }
625
+ }
626
+
627
+ addVisitedDataSpace(element: LegendQueryableElement): void {
628
+ try {
629
+ LegendQueryUserDataHelper.addVisitedDatspace(
630
+ this.applicationStore.userDataService,
631
+ createSimpleVisitedDataspace(
632
+ element.groupId,
633
+ element.artifactId,
634
+ element.versionId,
635
+ element.path,
636
+ element.execContext,
637
+ ),
638
+ );
639
+ } catch (error) {
640
+ assertErrorThrown(error);
641
+ this.applicationStore.logService.warn(
642
+ LogEvent.create(LEGEND_QUERY_APP_EVENT.LOCAL_STORAGE_PERSIST_ERROR),
643
+ error.message,
644
+ );
645
+ }
646
+ }
647
+
648
+ getPersistConfiguration(
649
+ lambda: RawLambda,
650
+ options?: { update?: boolean | undefined },
651
+ ): QueryPersistConfiguration | undefined {
652
+ const element = this.queryableElement;
653
+ if (element) {
654
+ return {
655
+ defaultName: options?.update
656
+ ? `${extractElementNameFromPath(element.path)}`
657
+ : `New Query for ${extractElementNameFromPath(element.path)}[${element.execContext}]`,
658
+ decorator: (query: Query): void => {
659
+ query.id = uuid();
660
+ query.groupId = element.groupId;
661
+ query.artifactId = element.artifactId;
662
+ query.versionId = element.versionId;
663
+ const taggedValues = [];
664
+ if (this.queryBuilderState?.class) {
665
+ taggedValues.push(
666
+ createQueryClassTaggedValue(this.queryBuilderState.class.path),
667
+ );
668
+ }
669
+ taggedValues.push(createQueryDataSpaceTaggedValue(element.path));
670
+ query.taggedValues = taggedValues;
671
+ },
672
+ };
673
+ }
674
+ return undefined;
675
+ }
676
+
677
+ override onInitializeFailure(): void {
678
+ // Remove the stale entry from the visited list
679
+ if (this.queryableElement) {
680
+ if (this.queryableElement instanceof QueryableDataProduct) {
681
+ LegendQueryUserDataHelper.removeRecentlyViewedDataProduct(
682
+ this.applicationStore.userDataService,
683
+ createVisitedDataProductId(
684
+ this.queryableElement.groupId,
685
+ this.queryableElement.artifactId,
686
+ this.queryableElement.path,
687
+ ),
688
+ );
689
+ } else {
690
+ LegendQueryUserDataHelper.removeRecentlyViewedDataSpace(
691
+ this.applicationStore.userDataService,
692
+ createVisitedDataSpaceId(
693
+ this.queryableElement.groupId,
694
+ this.queryableElement.artifactId,
695
+ this.queryableElement.path,
696
+ ),
697
+ );
698
+ }
699
+ }
700
+ // Reset so the user sees the bare selector with the data product /
701
+ // data space dropdown instead of a blank panel.
702
+ this.setQueryableElement(undefined);
703
+ const bareState = new LegendQueryBareQueryBuilderState(
704
+ this,
705
+ this.applicationStore,
706
+ this.graphManagerState,
707
+ this.depotServerClient,
708
+ {
709
+ onDataSpaceChange: (
710
+ dataSpaceInfo: ResolvedDataSpaceEntityWithOrigin,
711
+ ) => {
712
+ if (dataSpaceInfo.defaultExecutionContext) {
713
+ this.changeDataSpace(dataSpaceInfo);
714
+ } else {
715
+ this.applicationStore.notificationService.notifyWarning(
716
+ `Can't switch data product: default execution context not specified`,
717
+ );
718
+ }
719
+ },
720
+ onDataProductChange: (dataProductInfo: DepotEntityWithOrigin) => {
721
+ flowResult(this.changeDataProduct(dataProductInfo)).catch(
722
+ this.applicationStore.alertUnhandledError,
723
+ );
724
+ },
725
+ },
726
+ this.applicationStore.config.options.queryBuilderConfig,
727
+ this.productSelectorState,
728
+ );
729
+ this.queryBuilderState = bareState;
730
+ this.queryLoaderState.initialize(bareState);
731
+ // Mark as passed so the UI renders the query builder (with selector)
732
+ // instead of the loading/blank panel.
733
+ this.initState.pass();
734
+ }
735
+
736
+ override decorateSearchSpecification(
737
+ val: QuerySearchSpecification,
738
+ ): QuerySearchSpecification {
739
+ if (this.queryableElement) {
740
+ const currentProjectCoordinates = new QueryProjectCoordinates();
741
+ currentProjectCoordinates.groupId = this.queryableElement.groupId;
742
+ currentProjectCoordinates.artifactId = this.queryableElement.artifactId;
743
+ val.projectCoordinates = [
744
+ // either get queries for the current project
745
+ currentProjectCoordinates,
746
+ // or any of its dependencies
747
+ ...Array.from(
748
+ this.graphManagerState.graph.dependencyManager.projectDependencyModelsIndex.keys(),
749
+ ).map((dependencyKey) => {
750
+ const { groupId, artifactId } = parseGACoordinates(dependencyKey);
751
+ const coordinates = new QueryProjectCoordinates();
752
+ coordinates.groupId = groupId;
753
+ coordinates.artifactId = artifactId;
754
+ return coordinates;
755
+ }),
756
+ ];
757
+ val.taggedValues = [
758
+ createQueryDataSpaceTaggedValue(this.queryableElement.path),
759
+ ];
760
+ val.combineTaggedValuesCondition = true;
761
+ }
762
+
763
+ return val;
764
+ }
765
+ }