@finos/legend-application-query 13.8.52 → 13.8.53
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__/LegendQueryEvent.d.ts +6 -0
- package/lib/__lib__/LegendQueryEvent.d.ts.map +1 -1
- package/lib/__lib__/LegendQueryEvent.js +6 -0
- package/lib/__lib__/LegendQueryEvent.js.map +1 -1
- package/lib/__lib__/LegendQueryLifecycleTelemetry.d.ts +58 -0
- package/lib/__lib__/LegendQueryLifecycleTelemetry.d.ts.map +1 -0
- package/lib/__lib__/LegendQueryLifecycleTelemetry.js +90 -0
- package/lib/__lib__/LegendQueryLifecycleTelemetry.js.map +1 -0
- package/lib/__lib__/LegendQueryNavigation.d.ts +1 -1
- package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
- package/lib/__lib__/LegendQueryNavigation.js +11 -1
- package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
- package/lib/__lib__/LegendQuerySourceInfo.d.ts +137 -0
- package/lib/__lib__/LegendQuerySourceInfo.d.ts.map +1 -0
- package/lib/__lib__/LegendQuerySourceInfo.js +33 -0
- package/lib/__lib__/LegendQuerySourceInfo.js.map +1 -0
- package/lib/__lib__/LegendQueryTelemetryHelper.d.ts +73 -1
- package/lib/__lib__/LegendQueryTelemetryHelper.d.ts.map +1 -1
- package/lib/__lib__/LegendQueryTelemetryHelper.js +18 -0
- package/lib/__lib__/LegendQueryTelemetryHelper.js.map +1 -1
- package/lib/application/LegendQueryApplicationConfig.d.ts +2 -0
- package/lib/application/LegendQueryApplicationConfig.d.ts.map +1 -1
- package/lib/application/LegendQueryApplicationConfig.js +2 -0
- package/lib/application/LegendQueryApplicationConfig.js.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.js +13 -2
- package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/light-mode.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/EditExistingQuerySetupStore.d.ts.map +1 -1
- package/lib/stores/EditExistingQuerySetupStore.js +4 -13
- package/lib/stores/EditExistingQuerySetupStore.js.map +1 -1
- package/lib/stores/LegendQueryApplicationPlugin.d.ts +2 -1
- package/lib/stores/LegendQueryApplicationPlugin.d.ts.map +1 -1
- package/lib/stores/LegendQueryApplicationPlugin.js +23 -0
- package/lib/stores/LegendQueryApplicationPlugin.js.map +1 -1
- package/lib/stores/QueryEditorStore.d.ts +30 -2
- package/lib/stores/QueryEditorStore.d.ts.map +1 -1
- package/lib/stores/QueryEditorStore.js +123 -79
- package/lib/stores/QueryEditorStore.js.map +1 -1
- package/lib/stores/QueryProductionizerSetupStore.d.ts.map +1 -1
- package/lib/stores/QueryProductionizerSetupStore.js +4 -13
- package/lib/stores/QueryProductionizerSetupStore.js.map +1 -1
- package/lib/stores/QuerySetupStore.d.ts.map +1 -1
- package/lib/stores/QuerySetupStore.js +1 -0
- package/lib/stores/QuerySetupStore.js.map +1 -1
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts +2 -0
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts.map +1 -1
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js +12 -1
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js.map +1 -1
- package/lib/stores/data-space/DataProductQueryCreatorStore.d.ts +10 -0
- package/lib/stores/data-space/DataProductQueryCreatorStore.d.ts.map +1 -1
- package/lib/stores/data-space/DataProductQueryCreatorStore.js +63 -19
- package/lib/stores/data-space/DataProductQueryCreatorStore.js.map +1 -1
- package/lib/stores/data-space/DataProductSelectorState.d.ts +4 -2
- package/lib/stores/data-space/DataProductSelectorState.d.ts.map +1 -1
- package/lib/stores/data-space/DataProductSelectorState.js +30 -9
- package/lib/stores/data-space/DataProductSelectorState.js.map +1 -1
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts +2 -0
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts.map +1 -1
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js +13 -7
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js.map +1 -1
- package/lib/stores/data-space/LegendQueryBareQueryBuilderState.d.ts.map +1 -1
- package/lib/stores/data-space/LegendQueryBareQueryBuilderState.js +1 -1
- package/lib/stores/data-space/LegendQueryBareQueryBuilderState.js.map +1 -1
- package/lib/stores/ingest/IngestQueryCreatorStore.d.ts +2 -0
- package/lib/stores/ingest/IngestQueryCreatorStore.d.ts.map +1 -1
- package/lib/stores/ingest/IngestQueryCreatorStore.js +10 -3
- package/lib/stores/ingest/IngestQueryCreatorStore.js.map +1 -1
- package/package.json +13 -13
- package/src/__lib__/LegendQueryEvent.ts +7 -0
- package/src/__lib__/LegendQueryLifecycleTelemetry.ts +132 -0
- package/src/__lib__/LegendQueryNavigation.ts +20 -1
- package/src/__lib__/LegendQuerySourceInfo.ts +162 -0
- package/src/__lib__/LegendQueryTelemetryHelper.ts +120 -1
- package/src/application/LegendQueryApplicationConfig.ts +5 -1
- package/src/components/Core_LegendQueryApplicationPlugin.tsx +21 -2
- package/src/index.ts +6 -1
- package/src/stores/EditExistingQuerySetupStore.ts +8 -20
- package/src/stores/LegendQueryApplicationPlugin.tsx +38 -0
- package/src/stores/QueryEditorStore.ts +178 -86
- package/src/stores/QueryProductionizerSetupStore.ts +8 -20
- package/src/stores/QuerySetupStore.ts +2 -0
- package/src/stores/data-product/DataProductSampleQueryCreatorStore.ts +17 -0
- package/src/stores/data-space/DataProductQueryCreatorStore.ts +99 -33
- package/src/stores/data-space/DataProductSelectorState.ts +58 -13
- package/src/stores/data-space/DataSpaceTemplateQueryCreatorStore.ts +17 -6
- package/src/stores/data-space/LegendQueryBareQueryBuilderState.ts +5 -1
- package/src/stores/ingest/IngestQueryCreatorStore.ts +16 -5
- package/tsconfig.json +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finos/legend-application-query",
|
|
3
|
-
"version": "13.8.
|
|
3
|
+
"version": "13.8.53",
|
|
4
4
|
"description": "Legend Query application core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"legend",
|
|
@@ -44,18 +44,18 @@
|
|
|
44
44
|
"test:watch": "jest --watch"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@finos/legend-application": "16.0.
|
|
48
|
-
"@finos/legend-art": "7.1.
|
|
49
|
-
"@finos/legend-code-editor": "2.0.
|
|
50
|
-
"@finos/legend-data-cube": "0.3.
|
|
51
|
-
"@finos/legend-extension-dsl-data-space": "10.4.
|
|
52
|
-
"@finos/legend-graph": "32.
|
|
53
|
-
"@finos/legend-lego": "2.0.
|
|
54
|
-
"@finos/legend-query-builder": "4.19.
|
|
55
|
-
"@finos/legend-server-depot": "6.1.
|
|
56
|
-
"@finos/legend-server-lakehouse": "0.3.
|
|
57
|
-
"@finos/legend-shared": "11.0.
|
|
58
|
-
"@finos/legend-storage": "3.0.
|
|
47
|
+
"@finos/legend-application": "16.0.124",
|
|
48
|
+
"@finos/legend-art": "7.1.164",
|
|
49
|
+
"@finos/legend-code-editor": "2.0.204",
|
|
50
|
+
"@finos/legend-data-cube": "0.3.122",
|
|
51
|
+
"@finos/legend-extension-dsl-data-space": "10.4.256",
|
|
52
|
+
"@finos/legend-graph": "32.7.0",
|
|
53
|
+
"@finos/legend-lego": "2.0.224",
|
|
54
|
+
"@finos/legend-query-builder": "4.19.13",
|
|
55
|
+
"@finos/legend-server-depot": "6.1.21",
|
|
56
|
+
"@finos/legend-server-lakehouse": "0.3.84",
|
|
57
|
+
"@finos/legend-shared": "11.0.29",
|
|
58
|
+
"@finos/legend-storage": "3.0.151",
|
|
59
59
|
"@testing-library/dom": "10.4.0",
|
|
60
60
|
"@testing-library/react": "16.2.0",
|
|
61
61
|
"@types/react": "19.0.10",
|
|
@@ -22,7 +22,14 @@ export enum LEGEND_QUERY_APP_EVENT {
|
|
|
22
22
|
CREATE_QUERY__SUCCESS = 'query-editor.create-query.success',
|
|
23
23
|
UPDATE_QUERY__SUCCESS = 'query-editor.update-query.success',
|
|
24
24
|
RENAME_QUERY__SUCCESS = 'query-editor.rename.query.success',
|
|
25
|
+
DELETE_QUERY__SUCCESS = 'query-editor.delete-query.success',
|
|
26
|
+
|
|
27
|
+
CREATE_QUERY__FAILURE = 'query-editor.create-query.failure',
|
|
28
|
+
UPDATE_QUERY__FAILURE = 'query-editor.update-query.failure',
|
|
29
|
+
RENAME_QUERY__FAILURE = 'query-editor.rename-query.failure',
|
|
30
|
+
DELETE_QUERY__FAILURE = 'query-editor.delete-query.failure',
|
|
25
31
|
INITIALIZE_QUERY_STATE__SUCCESS = 'query-editor.initialize-query-state.success',
|
|
32
|
+
INITIALIZE_QUERY_CREATOR__FAILURE = 'query-editor.initialize-query-creator.failure',
|
|
26
33
|
LEGENDAI_QUERY_AGENT_CHAT__OPENED = 'query-editor.legendai-query-agent-chat.opened',
|
|
27
34
|
LEGENDAI_QUERY_AGENT_CHAT__QUERY_LOADED = 'query-editor.legendai-query-agent-chat.query-loaded',
|
|
28
35
|
LEGENDAI_QUERY_SUGGEST__LAUNCH = 'query-editor.legendai-query-suggest.launch',
|
|
@@ -0,0 +1,132 @@
|
|
|
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 type { LightQuery } from '@finos/legend-graph';
|
|
18
|
+
import { buildTelemetryErrorFields } from '@finos/legend-shared';
|
|
19
|
+
import type { GenericLegendApplicationStore } from '@finos/legend-application';
|
|
20
|
+
import type { CompleteQueryLoaderLifecycleHandlers } from '@finos/legend-query-builder';
|
|
21
|
+
import {
|
|
22
|
+
type PartialQuery_TelemetryData,
|
|
23
|
+
type QueryCreateFailure_TelemetryData,
|
|
24
|
+
type QueryLifecycleFailure_TelemetryData,
|
|
25
|
+
type Query_TelemetryData,
|
|
26
|
+
LegendQueryTelemetryHelper,
|
|
27
|
+
} from './LegendQueryTelemetryHelper.js';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Builds the error half of a saved-query lifecycle failure payload, applying the
|
|
31
|
+
* same message cap and `errorMessageTruncated` flag as every other failure event.
|
|
32
|
+
*/
|
|
33
|
+
export const buildQueryLifecycleFailureData = (
|
|
34
|
+
queryId: string,
|
|
35
|
+
error: Error,
|
|
36
|
+
): QueryLifecycleFailure_TelemetryData => ({
|
|
37
|
+
// NOTE: only the id is available on these paths — the loader reports a
|
|
38
|
+
// failure by id, and the query it refers to was never resolved
|
|
39
|
+
query: { id: queryId },
|
|
40
|
+
...buildTelemetryErrorFields(error),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Maps a query to the identity block every lifecycle event carries.
|
|
45
|
+
*/
|
|
46
|
+
export const buildQueryIdentity = (query: LightQuery): Query_TelemetryData => ({
|
|
47
|
+
query: {
|
|
48
|
+
id: query.id,
|
|
49
|
+
name: query.name,
|
|
50
|
+
groupId: query.groupId,
|
|
51
|
+
artifactId: query.artifactId,
|
|
52
|
+
versionId: query.versionId,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Builds the payload for a failed *create*.
|
|
58
|
+
*
|
|
59
|
+
* Separate from {@link buildQueryLifecycleFailureData} because a failed create
|
|
60
|
+
* has no query to identify — the server assigns the id and the request never got
|
|
61
|
+
* that far. Reporting the chosen name instead of a placeholder id keeps "never
|
|
62
|
+
* persisted" distinguishable from a real value.
|
|
63
|
+
*/
|
|
64
|
+
export const buildQueryCreateFailureData = (
|
|
65
|
+
queryName: string,
|
|
66
|
+
error: Error,
|
|
67
|
+
): QueryCreateFailure_TelemetryData => ({
|
|
68
|
+
queryName,
|
|
69
|
+
...buildTelemetryErrorFields(error),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The saved-query lifecycle handlers every `QueryLoaderState` host wires in.
|
|
74
|
+
*
|
|
75
|
+
* Rename and delete happen inside the shared query loader, which reports them
|
|
76
|
+
* back through callbacks — so without this the same emit would be duplicated at
|
|
77
|
+
* each of the three hosts that build a loader (and before this existed, the
|
|
78
|
+
* rename emit was in fact triplicated while delete was reported nowhere).
|
|
79
|
+
*
|
|
80
|
+
* NOTE: these events deliberately carry no source info. They fire from the query
|
|
81
|
+
* *picker*, where the user may rename or delete one query while editing another
|
|
82
|
+
* — attaching the loaded query builder's source info would silently mislabel the
|
|
83
|
+
* row as belonging to the wrong query.
|
|
84
|
+
*/
|
|
85
|
+
export const buildQueryLoaderLifecycleTelemetryHandlers = (
|
|
86
|
+
applicationStore: GenericLegendApplicationStore,
|
|
87
|
+
sideEffects?:
|
|
88
|
+
| {
|
|
89
|
+
/**
|
|
90
|
+
* Runs alongside the delete telemetry — hosts use this to prune their
|
|
91
|
+
* recently-viewed list.
|
|
92
|
+
*/
|
|
93
|
+
onQueryDeleted?: ((queryId: string) => void) | undefined;
|
|
94
|
+
}
|
|
95
|
+
| undefined,
|
|
96
|
+
): CompleteQueryLoaderLifecycleHandlers => {
|
|
97
|
+
const { telemetryService } = applicationStore;
|
|
98
|
+
return {
|
|
99
|
+
onQueryRenamed: (query): void => {
|
|
100
|
+
LegendQueryTelemetryHelper.logEvent_RenameQuerySucceeded(
|
|
101
|
+
telemetryService,
|
|
102
|
+
buildQueryIdentity(query),
|
|
103
|
+
);
|
|
104
|
+
},
|
|
105
|
+
onQueryDeleted: (queryId, deletedQuery): void => {
|
|
106
|
+
sideEffects?.onQueryDeleted?.(queryId);
|
|
107
|
+
// the entry may not have been in the loaded list, in which case only the
|
|
108
|
+
// id is known
|
|
109
|
+
const identity: PartialQuery_TelemetryData = deletedQuery
|
|
110
|
+
? buildQueryIdentity(deletedQuery)
|
|
111
|
+
: { query: { id: queryId } };
|
|
112
|
+
LegendQueryTelemetryHelper.logEvent_DeleteQuerySucceeded(
|
|
113
|
+
telemetryService,
|
|
114
|
+
identity,
|
|
115
|
+
);
|
|
116
|
+
},
|
|
117
|
+
onQueryRenameFailed: (queryId, error): void => {
|
|
118
|
+
// the rename failed, so the loader never resolved the renamed query —
|
|
119
|
+
// only its id and the error are known
|
|
120
|
+
LegendQueryTelemetryHelper.logEvent_RenameQueryFailed(
|
|
121
|
+
telemetryService,
|
|
122
|
+
buildQueryLifecycleFailureData(queryId, error),
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
onQueryDeleteFailed: (queryId, error): void => {
|
|
126
|
+
LegendQueryTelemetryHelper.logEvent_DeleteQueryFailed(
|
|
127
|
+
telemetryService,
|
|
128
|
+
buildQueryLifecycleFailureData(queryId, error),
|
|
129
|
+
);
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
};
|
|
@@ -442,6 +442,20 @@ export const EXTERNAL_APPLICATION_NAVIGATION__generateNewDataCubeUrl = (
|
|
|
442
442
|
)}`;
|
|
443
443
|
};
|
|
444
444
|
|
|
445
|
+
/**
|
|
446
|
+
* Mirrors `generateAnchorForSection` from `@finos/legend-extension-dsl-data-product`,
|
|
447
|
+
* which this package does not depend on. The data product viewer registers one anchor
|
|
448
|
+
* per access point group, and reads the zone from the URL hash on load.
|
|
449
|
+
*
|
|
450
|
+
* @external_application_navigation This depends on Legend Marketplace routing and is hardcoded so it's potentially brittle
|
|
451
|
+
*/
|
|
452
|
+
const EXTERNAL_APPLICATION_NAVIGATION__generateAccessPointGroupAnchor = (
|
|
453
|
+
accessPointGroupId: string,
|
|
454
|
+
): string =>
|
|
455
|
+
encodeURIComponent(
|
|
456
|
+
`apg-${accessPointGroupId}`.trim().toLowerCase().replace(/\s+/gu, '-'),
|
|
457
|
+
);
|
|
458
|
+
|
|
445
459
|
/**
|
|
446
460
|
* @external_application_navigation This depends on Legend Marketplace routing and is hardcoded so it's potentially brittle
|
|
447
461
|
*/
|
|
@@ -450,5 +464,10 @@ export const EXTERNAL_APPLICATION_NAVIGATION__generateMarketplaceDataProductUrl
|
|
|
450
464
|
marketplaceApplicationUrl: string,
|
|
451
465
|
dataProductId: string,
|
|
452
466
|
deploymentId: string,
|
|
467
|
+
accessPointGroupId?: string | undefined,
|
|
453
468
|
): string =>
|
|
454
|
-
`${marketplaceApplicationUrl}/dataProduct/deployed/${dataProductId}/${deploymentId}
|
|
469
|
+
`${marketplaceApplicationUrl}/dataProduct/deployed/${dataProductId}/${deploymentId}${
|
|
470
|
+
accessPointGroupId
|
|
471
|
+
? `#${EXTERNAL_APPLICATION_NAVIGATION__generateAccessPointGroupAnchor(accessPointGroupId)}`
|
|
472
|
+
: ''
|
|
473
|
+
}`;
|
|
@@ -0,0 +1,162 @@
|
|
|
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 type { LegendSourceInfo } from '@finos/legend-storage';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The entry point a query creator was started from.
|
|
21
|
+
*/
|
|
22
|
+
export enum LegendQuerySourceType {
|
|
23
|
+
MAPPING = 'mapping',
|
|
24
|
+
SERVICE = 'service',
|
|
25
|
+
DATA_SPACE = 'data-space',
|
|
26
|
+
DATA_SPACE_TEMPLATE = 'data-space.template',
|
|
27
|
+
DATA_PRODUCT = 'data-product',
|
|
28
|
+
DATA_PRODUCT_SAMPLE = 'data-product.sample',
|
|
29
|
+
INGEST = 'ingest',
|
|
30
|
+
/**
|
|
31
|
+
* The default route, when no data product or data space has been selected yet
|
|
32
|
+
*/
|
|
33
|
+
UNSELECTED = 'unselected',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Coordinates of the project the query is started from
|
|
38
|
+
*/
|
|
39
|
+
interface LegendQueryProjectSourceInfo extends LegendSourceInfo {
|
|
40
|
+
groupId: string;
|
|
41
|
+
artifactId: string;
|
|
42
|
+
versionId: string;
|
|
43
|
+
/**
|
|
44
|
+
* Set when a *saved* query was opened (the `/existing/:queryId` route) rather
|
|
45
|
+
* than a new one created from a creator route. The `sourceType` still
|
|
46
|
+
* describes what the query targets — a saved data space query reports
|
|
47
|
+
* `data-space`, same as a freshly created one — so a dashboard can slice by
|
|
48
|
+
* target without caring how the query was opened, and use the presence of
|
|
49
|
+
* this field to separate saved from new when it does care.
|
|
50
|
+
*/
|
|
51
|
+
queryId?: string | undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Query created on a mapping and runtime
|
|
56
|
+
* `/create/manual/:gav/:mappingPath/:runtimePath`
|
|
57
|
+
*/
|
|
58
|
+
export interface LegendQueryMappingSourceInfo
|
|
59
|
+
extends LegendQueryProjectSourceInfo {
|
|
60
|
+
sourceType: LegendQuerySourceType.MAPPING;
|
|
61
|
+
mapping: string;
|
|
62
|
+
runtime: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Query created from a service
|
|
67
|
+
* `/create-from-service/:gav/:servicePath`
|
|
68
|
+
*/
|
|
69
|
+
export interface LegendQueryServiceSourceInfo
|
|
70
|
+
extends LegendQueryProjectSourceInfo {
|
|
71
|
+
sourceType: LegendQuerySourceType.SERVICE;
|
|
72
|
+
service: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Query created on a data space
|
|
77
|
+
* `/dataspace/:gav/:dataSpacePath/:executionContext?`
|
|
78
|
+
*/
|
|
79
|
+
export interface LegendQueryDataSpaceSourceInfo
|
|
80
|
+
extends LegendQueryProjectSourceInfo {
|
|
81
|
+
sourceType: LegendQuerySourceType.DATA_SPACE;
|
|
82
|
+
dataSpace: string;
|
|
83
|
+
/**
|
|
84
|
+
* The key of the execution context the query was started with, when known
|
|
85
|
+
*/
|
|
86
|
+
executionContext?: string | undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Query created from a data space template query
|
|
91
|
+
* `/dataspace/:gav/:dataSpacePath/template/:templateQueryId`
|
|
92
|
+
*/
|
|
93
|
+
export interface LegendQueryDataSpaceTemplateSourceInfo
|
|
94
|
+
extends LegendQueryProjectSourceInfo {
|
|
95
|
+
sourceType: LegendQuerySourceType.DATA_SPACE_TEMPLATE;
|
|
96
|
+
dataSpace: string;
|
|
97
|
+
templateQueryId: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Query created on a data product
|
|
102
|
+
* `/data-product/:accessType/:gav/:dataProductPath/:accessId`
|
|
103
|
+
*/
|
|
104
|
+
export interface LegendQueryDataProductSourceInfo
|
|
105
|
+
extends LegendQueryProjectSourceInfo {
|
|
106
|
+
sourceType: LegendQuerySourceType.DATA_PRODUCT;
|
|
107
|
+
dataProduct: string;
|
|
108
|
+
/**
|
|
109
|
+
* The access type (e.g. native, model, lakehouse) the query was started
|
|
110
|
+
* with, when known
|
|
111
|
+
*/
|
|
112
|
+
accessType?: string | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* The ID of the access point (group) or execution context the query was
|
|
115
|
+
* started with, when known
|
|
116
|
+
*/
|
|
117
|
+
accessId?: string | undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Query created from a data product sample query
|
|
122
|
+
* `/data-product/native/sample-query/:gav/:dataProductPath/:sampleQueryId`
|
|
123
|
+
*/
|
|
124
|
+
export interface LegendQueryDataProductSampleSourceInfo
|
|
125
|
+
extends LegendQueryProjectSourceInfo {
|
|
126
|
+
sourceType: LegendQuerySourceType.DATA_PRODUCT_SAMPLE;
|
|
127
|
+
dataProduct: string;
|
|
128
|
+
sampleQueryId: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Query created on an ingest data set
|
|
133
|
+
* `/ingest/:gav/:ingestDefinitionPath/:dataSet`
|
|
134
|
+
*/
|
|
135
|
+
export interface LegendQueryIngestSourceInfo
|
|
136
|
+
extends LegendQueryProjectSourceInfo {
|
|
137
|
+
sourceType: LegendQuerySourceType.INGEST;
|
|
138
|
+
ingestDefinitionPath: string;
|
|
139
|
+
dataSet: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The default route `/`, when no data product or data space has been
|
|
144
|
+
* selected yet
|
|
145
|
+
*/
|
|
146
|
+
export interface LegendQueryUnselectedSourceInfo extends LegendSourceInfo {
|
|
147
|
+
sourceType: LegendQuerySourceType.UNSELECTED;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Where a query creator was started from, used as the query builder state
|
|
152
|
+
* source info (see `QueryBuilderState.sourceInfo`) and reported in telemetry
|
|
153
|
+
*/
|
|
154
|
+
export type LegendQuerySourceInfo =
|
|
155
|
+
| LegendQueryMappingSourceInfo
|
|
156
|
+
| LegendQueryServiceSourceInfo
|
|
157
|
+
| LegendQueryDataSpaceSourceInfo
|
|
158
|
+
| LegendQueryDataSpaceTemplateSourceInfo
|
|
159
|
+
| LegendQueryDataProductSourceInfo
|
|
160
|
+
| LegendQueryDataProductSampleSourceInfo
|
|
161
|
+
| LegendQueryIngestSourceInfo
|
|
162
|
+
| LegendQueryUnselectedSourceInfo;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import type { TelemetryService } from '@finos/legend-application';
|
|
18
|
+
import type { TelemetryErrorFields, TimingsRecord } from '@finos/legend-shared';
|
|
18
19
|
import { LEGEND_QUERY_APP_EVENT } from './LegendQueryEvent.js';
|
|
19
20
|
import {
|
|
20
21
|
type GraphManagerOperationReport,
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
type GraphInitializationReport,
|
|
23
24
|
} from '@finos/legend-graph';
|
|
24
25
|
|
|
25
|
-
type Query_TelemetryData = {
|
|
26
|
+
export type Query_TelemetryData = {
|
|
26
27
|
query: {
|
|
27
28
|
name: string;
|
|
28
29
|
id: string;
|
|
@@ -46,6 +47,79 @@ type IntializeQueryState_TelemetryData = Query_TelemetryData &
|
|
|
46
47
|
dependenciesCount: number;
|
|
47
48
|
};
|
|
48
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Where the query creator was started from, returned by each creator store's
|
|
52
|
+
* `getInitializeTelemetrySource()`.
|
|
53
|
+
*
|
|
54
|
+
* The entry point the query creator was started from ({@link
|
|
55
|
+
* LegendQuerySourceInfo}) is spread FLAT into this payload, matching how
|
|
56
|
+
* `sourceInfo` is reported on every other query telemetry event.
|
|
57
|
+
*
|
|
58
|
+
* The index signature is what allows those flat keys — they vary by entry point
|
|
59
|
+
* and `LegendQuerySourceInfo` is a union, so they cannot be enumerated here.
|
|
60
|
+
* The union stays strictly typed where it is built, in each creator store's
|
|
61
|
+
* `getSourceInfo()` override.
|
|
62
|
+
*/
|
|
63
|
+
export type InitializeTelemetrySource = Record<PropertyKey, unknown> & {
|
|
64
|
+
/**
|
|
65
|
+
* Whether the most recently visited source was reopened, rather than the
|
|
66
|
+
* source being specified by the route
|
|
67
|
+
*/
|
|
68
|
+
restoredFromRecent: boolean;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Base payload for the query creator failure event.
|
|
73
|
+
*
|
|
74
|
+
* There is no success counterpart: a successful load is reported by
|
|
75
|
+
* `query-builder.opened` from `legend-query-builder`, which fires for every
|
|
76
|
+
* route rather than creators only. This one survives because when a load fails
|
|
77
|
+
* there is no query builder to emit from, so it is the only record that an
|
|
78
|
+
* attempt happened.
|
|
79
|
+
*/
|
|
80
|
+
export type InitializeQueryCreator_TelemetryData = InitializeTelemetrySource & {
|
|
81
|
+
timings: TimingsRecord;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export type InitializeQueryCreatorFailure_TelemetryData =
|
|
85
|
+
InitializeQueryCreator_TelemetryData & TelemetryErrorFields;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The query a lifecycle event acted on. `id` is always known for update, rename
|
|
89
|
+
* and delete — they act on a query that already exists. Identity beyond the id
|
|
90
|
+
* is partial: a delete resolves the entry from the loaded list, which may not
|
|
91
|
+
* contain it.
|
|
92
|
+
*/
|
|
93
|
+
export type PartialQuery_TelemetryData = {
|
|
94
|
+
query: {
|
|
95
|
+
id: string;
|
|
96
|
+
name?: string | undefined;
|
|
97
|
+
versionId?: string | undefined;
|
|
98
|
+
groupId?: string | undefined;
|
|
99
|
+
artifactId?: string | undefined;
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Payload for a failed *create*.
|
|
105
|
+
*
|
|
106
|
+
* Deliberately has no `query` block: the server assigns the id, and a failed
|
|
107
|
+
* create never got that far, so no query exists to identify. The name the user
|
|
108
|
+
* chose is the only identity there is. Keeping this a separate type from
|
|
109
|
+
* {@link QueryLifecycleFailure_TelemetryData} means the three events that *do*
|
|
110
|
+
* always have an id cannot accidentally omit it.
|
|
111
|
+
*/
|
|
112
|
+
export type QueryCreateFailure_TelemetryData = {
|
|
113
|
+
queryName: string;
|
|
114
|
+
} & TelemetryErrorFields;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Payload for a failed update, rename or delete — actions on a query that
|
|
118
|
+
* already exists, so `query.id` is always present.
|
|
119
|
+
*/
|
|
120
|
+
export type QueryLifecycleFailure_TelemetryData = PartialQuery_TelemetryData &
|
|
121
|
+
TelemetryErrorFields;
|
|
122
|
+
|
|
49
123
|
export class LegendQueryTelemetryHelper {
|
|
50
124
|
static logEvent_ViewQuerySucceeded(
|
|
51
125
|
service: TelemetryService,
|
|
@@ -64,6 +138,16 @@ export class LegendQueryTelemetryHelper {
|
|
|
64
138
|
);
|
|
65
139
|
}
|
|
66
140
|
|
|
141
|
+
static logEvent_InitializeQueryCreatorFailed(
|
|
142
|
+
service: TelemetryService,
|
|
143
|
+
data: InitializeQueryCreatorFailure_TelemetryData,
|
|
144
|
+
): void {
|
|
145
|
+
service.logEvent(
|
|
146
|
+
LEGEND_QUERY_APP_EVENT.INITIALIZE_QUERY_CREATOR__FAILURE,
|
|
147
|
+
data,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
67
151
|
static logEvent_CreateQuerySucceeded(
|
|
68
152
|
service: TelemetryService,
|
|
69
153
|
data: Query_TelemetryData,
|
|
@@ -109,6 +193,41 @@ export class LegendQueryTelemetryHelper {
|
|
|
109
193
|
service.logEvent(LEGEND_QUERY_APP_EVENT.RENAME_QUERY__SUCCESS, data);
|
|
110
194
|
}
|
|
111
195
|
|
|
196
|
+
static logEvent_DeleteQuerySucceeded(
|
|
197
|
+
service: TelemetryService,
|
|
198
|
+
data: PartialQuery_TelemetryData,
|
|
199
|
+
): void {
|
|
200
|
+
service.logEvent(LEGEND_QUERY_APP_EVENT.DELETE_QUERY__SUCCESS, data);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static logEvent_CreateQueryFailed(
|
|
204
|
+
service: TelemetryService,
|
|
205
|
+
data: QueryCreateFailure_TelemetryData,
|
|
206
|
+
): void {
|
|
207
|
+
service.logEvent(LEGEND_QUERY_APP_EVENT.CREATE_QUERY__FAILURE, data);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
static logEvent_UpdateQueryFailed(
|
|
211
|
+
service: TelemetryService,
|
|
212
|
+
data: QueryLifecycleFailure_TelemetryData,
|
|
213
|
+
): void {
|
|
214
|
+
service.logEvent(LEGEND_QUERY_APP_EVENT.UPDATE_QUERY__FAILURE, data);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static logEvent_RenameQueryFailed(
|
|
218
|
+
service: TelemetryService,
|
|
219
|
+
data: QueryLifecycleFailure_TelemetryData,
|
|
220
|
+
): void {
|
|
221
|
+
service.logEvent(LEGEND_QUERY_APP_EVENT.RENAME_QUERY__FAILURE, data);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
static logEvent_DeleteQueryFailed(
|
|
225
|
+
service: TelemetryService,
|
|
226
|
+
data: QueryLifecycleFailure_TelemetryData,
|
|
227
|
+
): void {
|
|
228
|
+
service.logEvent(LEGEND_QUERY_APP_EVENT.DELETE_QUERY__FAILURE, data);
|
|
229
|
+
}
|
|
230
|
+
|
|
112
231
|
static logEvent_QueryAISuggestLaunched(service: TelemetryService): void {
|
|
113
232
|
service.logEvent(LEGEND_QUERY_APP_EVENT.LEGENDAI_QUERY_SUGGEST__LAUNCH, {});
|
|
114
233
|
}
|
|
@@ -142,7 +142,7 @@ export interface LegendQueryApplicationConfigurationData
|
|
|
142
142
|
depot: {
|
|
143
143
|
url: string;
|
|
144
144
|
};
|
|
145
|
-
engine: { url: string; queryUrl?: string };
|
|
145
|
+
engine: { url: string; queryUrl?: string; useCookieAuthOnly?: boolean };
|
|
146
146
|
studio: {
|
|
147
147
|
url: string;
|
|
148
148
|
instances: LegendStudioApplicationInstanceConfigurationData[];
|
|
@@ -171,6 +171,7 @@ export class LegendQueryApplicationConfig extends LegendApplicationConfig {
|
|
|
171
171
|
|
|
172
172
|
readonly engineServerUrl: string;
|
|
173
173
|
readonly engineQueryServerUrl?: string | undefined;
|
|
174
|
+
readonly engineUseCookieAuthOnly: boolean;
|
|
174
175
|
readonly depotServerUrl: string;
|
|
175
176
|
readonly studioApplicationUrl: string;
|
|
176
177
|
readonly taxonomyApplicationUrl?: string;
|
|
@@ -204,6 +205,9 @@ export class LegendQueryApplicationConfig extends LegendApplicationConfig {
|
|
|
204
205
|
input.configData.engine.queryUrl,
|
|
205
206
|
)
|
|
206
207
|
: undefined;
|
|
208
|
+
this.engineUseCookieAuthOnly = Boolean(
|
|
209
|
+
input.configData.engine.useCookieAuthOnly,
|
|
210
|
+
);
|
|
207
211
|
|
|
208
212
|
// depot
|
|
209
213
|
assertNonNullable(
|
|
@@ -141,6 +141,19 @@ import { LegendQueryDataProductQueryBuilderState } from '../stores/data-product/
|
|
|
141
141
|
import { IngestLegendQueryBuilderState } from '../stores/ingest/IngestLegendQueryBuilderState.js';
|
|
142
142
|
import { renderDataProductSampleQueryPanelContent } from './data-product/DataProductSampleQueryPanel.js';
|
|
143
143
|
|
|
144
|
+
const isDataProductOrIngestQuery = (
|
|
145
|
+
queryBuilderState: QueryBuilderState,
|
|
146
|
+
): boolean =>
|
|
147
|
+
queryBuilderState instanceof DataProductQueryBuilderState ||
|
|
148
|
+
queryBuilderState instanceof IngestLegendQueryBuilderState;
|
|
149
|
+
|
|
150
|
+
const getUnsupportedExportActionMessage = (
|
|
151
|
+
queryBuilderState: QueryBuilderState,
|
|
152
|
+
): string =>
|
|
153
|
+
isDataProductOrIngestQuery(queryBuilderState)
|
|
154
|
+
? 'Not supported for Data Product or Ingest queries'
|
|
155
|
+
: 'Requires saved query';
|
|
156
|
+
|
|
144
157
|
export const QUERY_DATACUBE_USAGE_TITLE = 'Legend DataCube';
|
|
145
158
|
const QUERY_DATACUBE_SOURCE_TYPE = 'legendQuery';
|
|
146
159
|
|
|
@@ -387,6 +400,9 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
|
|
|
387
400
|
title: 'Promote Curated Template query...',
|
|
388
401
|
label: 'Curated Template Query',
|
|
389
402
|
disableFunc: (queryBuilderState): boolean => {
|
|
403
|
+
if (isDataProductOrIngestQuery(queryBuilderState)) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
390
406
|
if (
|
|
391
407
|
queryBuilderState.workflowState.actionConfig instanceof
|
|
392
408
|
QueryBuilderActionConfig_QueryApplication
|
|
@@ -463,13 +479,16 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
|
|
|
463
479
|
}
|
|
464
480
|
},
|
|
465
481
|
icon: <ArrowCircleUpIcon />,
|
|
466
|
-
|
|
482
|
+
getDisableMessage: getUnsupportedExportActionMessage,
|
|
467
483
|
},
|
|
468
484
|
{
|
|
469
485
|
key: 'legend-datacube-query',
|
|
470
486
|
title: 'Launch Legend DataCube...',
|
|
471
487
|
label: 'Legend DataCube',
|
|
472
488
|
disableFunc: (queryBuilderState): boolean => {
|
|
489
|
+
if (isDataProductOrIngestQuery(queryBuilderState)) {
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
473
492
|
if (
|
|
474
493
|
queryBuilderState.workflowState.actionConfig instanceof
|
|
475
494
|
QueryBuilderActionConfig_QueryApplication
|
|
@@ -515,7 +534,7 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
|
|
|
515
534
|
}
|
|
516
535
|
},
|
|
517
536
|
icon: <CubeIcon />,
|
|
518
|
-
|
|
537
|
+
getDisableMessage: getUnsupportedExportActionMessage,
|
|
519
538
|
},
|
|
520
539
|
];
|
|
521
540
|
}
|
package/src/index.ts
CHANGED
|
@@ -21,7 +21,12 @@ export * from './application/LegendQueryPluginManager.js';
|
|
|
21
21
|
|
|
22
22
|
export * from './__lib__/LegendQueryEvent.js';
|
|
23
23
|
export * from './__lib__/LegendQueryEventHelper.js';
|
|
24
|
-
export {
|
|
24
|
+
export {
|
|
25
|
+
LegendQueryTelemetryHelper,
|
|
26
|
+
type InitializeQueryCreator_TelemetryData,
|
|
27
|
+
type InitializeQueryCreatorFailure_TelemetryData,
|
|
28
|
+
} from './__lib__/LegendQueryTelemetryHelper.js';
|
|
29
|
+
export * from './__lib__/LegendQuerySourceInfo.js';
|
|
25
30
|
export { LegendQueryAgentChatTelemetryHelper } from './__lib__/LegendQueryAgentChatTelemetryHelper.js';
|
|
26
31
|
export {
|
|
27
32
|
generateExistingQueryEditorRoute,
|
|
@@ -22,10 +22,10 @@ import { BaseQuerySetupStore } from './QuerySetupStore.js';
|
|
|
22
22
|
import type { DepotServerClient } from '@finos/legend-server-depot';
|
|
23
23
|
import { quantifyList } from '@finos/legend-shared';
|
|
24
24
|
import { LegendQueryUserDataHelper } from '../__lib__/LegendQueryUserDataHelper.js';
|
|
25
|
+
import { buildQueryLoaderLifecycleTelemetryHandlers } from '../__lib__/LegendQueryLifecycleTelemetry.js';
|
|
25
26
|
import type { LegendQueryApplicationStore } from './LegendQueryBaseStore.js';
|
|
26
27
|
import { QuerySearchSpecification, type LightQuery } from '@finos/legend-graph';
|
|
27
28
|
import { generateExistingQueryEditorRoute } from '../__lib__/LegendQueryNavigation.js';
|
|
28
|
-
import { LegendQueryTelemetryHelper } from '../__lib__/LegendQueryTelemetryHelper.js';
|
|
29
29
|
|
|
30
30
|
export class EditExistingQuerySetupStore extends BaseQuerySetupStore {
|
|
31
31
|
readonly queryLoaderState: QueryLoaderState;
|
|
@@ -74,25 +74,13 @@ export class EditExistingQuerySetupStore extends BaseQuerySetupStore {
|
|
|
74
74
|
'recently viewed queries',
|
|
75
75
|
)}`
|
|
76
76
|
: `No recently viewed queries`,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
applicationStore.telemetryService,
|
|
85
|
-
{
|
|
86
|
-
query: {
|
|
87
|
-
id: query.id,
|
|
88
|
-
name: query.name,
|
|
89
|
-
groupId: query.groupId,
|
|
90
|
-
artifactId: query.artifactId,
|
|
91
|
-
versionId: query.versionId,
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
);
|
|
95
|
-
},
|
|
77
|
+
...buildQueryLoaderLifecycleTelemetryHandlers(this.applicationStore, {
|
|
78
|
+
onQueryDeleted: (queryId): void =>
|
|
79
|
+
LegendQueryUserDataHelper.removeRecentlyViewedQuery(
|
|
80
|
+
this.applicationStore.userDataService,
|
|
81
|
+
queryId,
|
|
82
|
+
),
|
|
83
|
+
}),
|
|
96
84
|
handleFetchDefaultQueriesFailure: (): void =>
|
|
97
85
|
LegendQueryUserDataHelper.removeRecentlyViewedQueries(
|
|
98
86
|
this.applicationStore.userDataService,
|