@finos/legend-application-query 13.8.29 → 13.8.30

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 (66) hide show
  1. package/lib/__lib__/LegendQueryNavigation.d.ts +12 -0
  2. package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
  3. package/lib/__lib__/LegendQueryNavigation.js +16 -0
  4. package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
  5. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
  6. package/lib/components/Core_LegendQueryApplicationPlugin.js +15 -0
  7. package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
  8. package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
  9. package/lib/components/LegendQueryWebApplication.js +2 -1
  10. package/lib/components/LegendQueryWebApplication.js.map +1 -1
  11. package/lib/components/QueryEditor.d.ts.map +1 -1
  12. package/lib/components/QueryEditor.js +5 -1
  13. package/lib/components/QueryEditor.js.map +1 -1
  14. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.d.ts.map +1 -1
  15. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js +6 -40
  16. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js.map +1 -1
  17. package/lib/components/ingest/IngestInfo.d.ts +32 -0
  18. package/lib/components/ingest/IngestInfo.d.ts.map +1 -0
  19. package/lib/components/ingest/IngestInfo.js +63 -0
  20. package/lib/components/ingest/IngestInfo.js.map +1 -0
  21. package/lib/components/ingest/IngestQueryBuilderSetupPanel.d.ts +18 -0
  22. package/lib/components/ingest/IngestQueryBuilderSetupPanel.d.ts.map +1 -0
  23. package/lib/components/ingest/IngestQueryBuilderSetupPanel.js +77 -0
  24. package/lib/components/ingest/IngestQueryBuilderSetupPanel.js.map +1 -0
  25. package/lib/components/ingest/IngestQueryCreator.d.ts +27 -0
  26. package/lib/components/ingest/IngestQueryCreator.d.ts.map +1 -0
  27. package/lib/components/ingest/IngestQueryCreator.js +45 -0
  28. package/lib/components/ingest/IngestQueryCreator.js.map +1 -0
  29. package/lib/components/shared/LakehouseRuntimeConfigModal.d.ts +29 -0
  30. package/lib/components/shared/LakehouseRuntimeConfigModal.d.ts.map +1 -0
  31. package/lib/components/shared/LakehouseRuntimeConfigModal.js +60 -0
  32. package/lib/components/shared/LakehouseRuntimeConfigModal.js.map +1 -0
  33. package/lib/index.css +1 -1
  34. package/lib/light-mode.css +1 -1
  35. package/lib/package.json +1 -1
  36. package/lib/stores/QueryEditorStore.d.ts +10 -0
  37. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  38. package/lib/stores/QueryEditorStore.js +81 -2
  39. package/lib/stores/QueryEditorStore.js.map +1 -1
  40. package/lib/stores/ingest/IngestLegendQueryBuilderState.d.ts +122 -0
  41. package/lib/stores/ingest/IngestLegendQueryBuilderState.d.ts.map +1 -0
  42. package/lib/stores/ingest/IngestLegendQueryBuilderState.js +191 -0
  43. package/lib/stores/ingest/IngestLegendQueryBuilderState.js.map +1 -0
  44. package/lib/stores/ingest/IngestQueryCreatorStore.d.ts +75 -0
  45. package/lib/stores/ingest/IngestQueryCreatorStore.d.ts.map +1 -0
  46. package/lib/stores/ingest/IngestQueryCreatorStore.js +169 -0
  47. package/lib/stores/ingest/IngestQueryCreatorStore.js.map +1 -0
  48. package/lib/stores/ingest/IngestQueryGraphHelper.d.ts +58 -0
  49. package/lib/stores/ingest/IngestQueryGraphHelper.d.ts.map +1 -0
  50. package/lib/stores/ingest/IngestQueryGraphHelper.js +72 -0
  51. package/lib/stores/ingest/IngestQueryGraphHelper.js.map +1 -0
  52. package/package.json +12 -12
  53. package/src/__lib__/LegendQueryNavigation.ts +35 -0
  54. package/src/components/Core_LegendQueryApplicationPlugin.tsx +20 -0
  55. package/src/components/LegendQueryWebApplication.tsx +14 -0
  56. package/src/components/QueryEditor.tsx +12 -0
  57. package/src/components/data-product/LegendQueryDataProductQueryBuilder.tsx +7 -127
  58. package/src/components/ingest/IngestInfo.tsx +197 -0
  59. package/src/components/ingest/IngestQueryBuilderSetupPanel.tsx +204 -0
  60. package/src/components/ingest/IngestQueryCreator.tsx +75 -0
  61. package/src/components/shared/LakehouseRuntimeConfigModal.tsx +148 -0
  62. package/src/stores/QueryEditorStore.ts +131 -1
  63. package/src/stores/ingest/IngestLegendQueryBuilderState.ts +259 -0
  64. package/src/stores/ingest/IngestQueryCreatorStore.ts +262 -0
  65. package/src/stores/ingest/IngestQueryGraphHelper.ts +120 -0
  66. package/tsconfig.json +7 -0
@@ -0,0 +1,204 @@
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 { useApplicationStore } from '@finos/legend-application';
18
+ import {
19
+ AnchorLinkIcon,
20
+ CogIcon,
21
+ compareLabelFn,
22
+ ControlledDropdownMenu,
23
+ createFilter,
24
+ CustomSelectorInput,
25
+ MenuContent,
26
+ MenuContentItem,
27
+ MenuContentItemIcon,
28
+ MenuContentItemLabel,
29
+ MoreVerticalIcon,
30
+ PanelHeader,
31
+ PanelHeaderActionItem,
32
+ PanelHeaderActions,
33
+ } from '@finos/legend-art';
34
+ import { observer } from 'mobx-react-lite';
35
+ import { useState } from 'react';
36
+ import type { IngestLegendQueryBuilderState } from '../../stores/ingest/IngestLegendQueryBuilderState.js';
37
+ import { LakehouseRuntimeConfigModal } from '../shared/LakehouseRuntimeConfigModal.js';
38
+
39
+ type DataSetOption = {
40
+ label: string;
41
+ value: { schemaName?: string | undefined; tableName: string };
42
+ };
43
+
44
+ type IngestOption = {
45
+ label: string;
46
+ value: string;
47
+ };
48
+
49
+ /**
50
+ * Setup panel for ingest-backed queries. Mirrors the data-product setup
51
+ * panel's header actions (copy deep-link, edit lakehouse runtime) but
52
+ * skips the source / runtime selectors since the ingest flow is fully
53
+ * resolved from the route + adhoc runtime. The data set selector is kept
54
+ * so the user can switch between datasets of the same ingest definition.
55
+ */
56
+ const IngestQueryBuilderSetupPanelContent = observer(
57
+ (props: { queryBuilderState: IngestLegendQueryBuilderState }) => {
58
+ const { queryBuilderState } = props;
59
+ const applicationStore = useApplicationStore();
60
+ const [isLakehouseConfigModalOpen, setIsLakehouseConfigModalOpen] =
61
+ useState(false);
62
+ const lakehouseRuntime = queryBuilderState.lakehouseRuntime;
63
+ const showLakehouseConfigButton = Boolean(lakehouseRuntime);
64
+ const darkMode =
65
+ !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled;
66
+
67
+ // data set selector (driven by the ingest definition's datasets via
68
+ // `AccessorQueryBuilderState.accessorsOptions`).
69
+ const dataSetOptions =
70
+ queryBuilderState.accessorsOptions.sort(compareLabelFn);
71
+ const selectedDataSetOption = queryBuilderState.sourceAccessor
72
+ ? (dataSetOptions.find(
73
+ (opt) =>
74
+ opt.value.tableName ===
75
+ queryBuilderState.sourceAccessor?.accessor &&
76
+ opt.value.schemaName === queryBuilderState.sourceAccessor.schema,
77
+ ) ?? null)
78
+ : null;
79
+ const changeDataSet = async (val: DataSetOption): Promise<void> => {
80
+ await queryBuilderState.changeAccessor(val.value);
81
+ };
82
+
83
+ // ingest selector (paths fetched up front; only one ingest is built into
84
+ // the graph at a time — see `IngestQueryCreatorStore.swapIngestDefinition`).
85
+ const ingestOptions: IngestOption[] = queryBuilderState.allIngestPaths
86
+ .map((path) => ({ label: path, value: path }))
87
+ .sort(compareLabelFn);
88
+ const selectedIngestOption: IngestOption | null =
89
+ ingestOptions.find(
90
+ (opt) => opt.value === queryBuilderState.ingestDefinition.path,
91
+ ) ?? null;
92
+ const changeIngest = async (val: IngestOption): Promise<void> => {
93
+ await queryBuilderState.changeIngestDefinition(val.value);
94
+ };
95
+ const ingestFilterOption = createFilter({
96
+ ignoreCase: true,
97
+ ignoreAccents: false,
98
+ stringify: (option: { data: IngestOption }): string => option.data.value,
99
+ });
100
+
101
+ return (
102
+ <div className="query-builder__setup__config-group">
103
+ <PanelHeader title="properties">
104
+ <PanelHeaderActions>
105
+ <PanelHeaderActionItem
106
+ title="copy ingest query set up link to clipboard"
107
+ onClick={() => queryBuilderState.copyIngestQueryLinkToClipBoard()}
108
+ >
109
+ <AnchorLinkIcon />
110
+ </PanelHeaderActionItem>
111
+ {showLakehouseConfigButton && (
112
+ <ControlledDropdownMenu
113
+ className="panel__header__action query-builder__setup__config-group__header__dropdown-trigger"
114
+ title="Show Settings..."
115
+ content={
116
+ <MenuContent>
117
+ <MenuContentItem
118
+ onClick={() => setIsLakehouseConfigModalOpen(true)}
119
+ >
120
+ <MenuContentItemIcon>
121
+ <CogIcon />
122
+ </MenuContentItemIcon>
123
+ <MenuContentItemLabel>
124
+ Lakehouse Runtime Configuration
125
+ </MenuContentItemLabel>
126
+ </MenuContentItem>
127
+ </MenuContent>
128
+ }
129
+ menuProps={{
130
+ anchorOrigin: {
131
+ vertical: 'bottom',
132
+ horizontal: 'right',
133
+ },
134
+ transformOrigin: {
135
+ vertical: 'top',
136
+ horizontal: 'right',
137
+ },
138
+ }}
139
+ >
140
+ <MoreVerticalIcon className="query-builder__icon__more-options" />
141
+ </ControlledDropdownMenu>
142
+ )}
143
+ </PanelHeaderActions>
144
+ </PanelHeader>
145
+ <div className="query-builder__setup__config-group__content">
146
+ <div className="query-builder__setup__config-group__item">
147
+ <label
148
+ className="btn--sm query-builder__setup__config-group__item__label"
149
+ title="ingest definition"
150
+ htmlFor="query-builder__setup__ingest-selector"
151
+ >
152
+ Ingest
153
+ </label>
154
+ <CustomSelectorInput
155
+ inputId="query-builder__setup__ingest-selector"
156
+ className="panel__content__form__section__dropdown query-builder__setup__config-group__item__selector"
157
+ placeholder="Choose an ingest..."
158
+ options={ingestOptions}
159
+ onChange={(val: IngestOption): void => {
160
+ changeIngest(val).catch(() => undefined);
161
+ }}
162
+ value={selectedIngestOption}
163
+ darkMode={darkMode}
164
+ disabled={queryBuilderState.isSwappingIngest}
165
+ filterOption={ingestFilterOption}
166
+ />
167
+ </div>
168
+ <div className="query-builder__setup__config-group__item">
169
+ <label
170
+ className="btn--sm query-builder__setup__config-group__item__label"
171
+ title="data set"
172
+ htmlFor="query-builder__setup__ingest-dataset-selector"
173
+ >
174
+ Data Set
175
+ </label>
176
+ <CustomSelectorInput
177
+ inputId="query-builder__setup__ingest-dataset-selector"
178
+ className="panel__content__form__section__dropdown query-builder__setup__config-group__item__selector"
179
+ placeholder="Choose a data set..."
180
+ options={dataSetOptions}
181
+ onChange={(val: DataSetOption): void => {
182
+ changeDataSet(val).catch(() => undefined);
183
+ }}
184
+ value={selectedDataSetOption}
185
+ darkMode={darkMode}
186
+ />
187
+ </div>
188
+ </div>
189
+ <LakehouseRuntimeConfigModal
190
+ lakehouseRuntime={lakehouseRuntime}
191
+ open={isLakehouseConfigModalOpen}
192
+ onClose={() => setIsLakehouseConfigModalOpen(false)}
193
+ darkMode={darkMode}
194
+ />
195
+ </div>
196
+ );
197
+ },
198
+ );
199
+
200
+ export const renderIngestQueryBuilderSetupPanelContent = (
201
+ queryBuilderState: IngestLegendQueryBuilderState,
202
+ ): React.ReactNode => (
203
+ <IngestQueryBuilderSetupPanelContent queryBuilderState={queryBuilderState} />
204
+ );
@@ -0,0 +1,75 @@
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 { observer, useLocalObservable } from 'mobx-react-lite';
18
+ import { parseGAVCoordinates } from '@finos/legend-storage';
19
+ import { guaranteeNonNullable } from '@finos/legend-shared';
20
+ import {
21
+ useLegendQueryApplicationStore,
22
+ useLegendQueryBaseStore,
23
+ } from '../LegendQueryFrameworkProvider.js';
24
+ import {
25
+ INGEST_QUERY_CREATOR_ROUTE_PATTERN_TOKEN,
26
+ type IngestQueryCreatorPathParams,
27
+ } from '../../__lib__/LegendQueryNavigation.js';
28
+ import { IngestQueryCreatorStore } from '../../stores/ingest/IngestQueryCreatorStore.js';
29
+ import { QueryEditorStoreContext } from '../QueryEditorStoreProvider.js';
30
+ import { QueryEditor } from '../QueryEditor.js';
31
+ import { useParams } from '@finos/legend-application/browser';
32
+
33
+ /**
34
+ * Route handler for `LEGEND_QUERY_ROUTE_PATTERN.INGEST_QUERY`.
35
+ *
36
+ * Parses `gav`, `ingestDefinitionPath` and `dataSet` from the URL, builds an
37
+ * {@link IngestQueryCreatorStore}, and renders the shared {@link QueryEditor}
38
+ * against it. The store fetches only the ingest definition entity from Depot
39
+ * — no full graph build.
40
+ */
41
+ export const IngestQueryCreator = observer(() => {
42
+ const applicationStore = useLegendQueryApplicationStore();
43
+ const baseStore = useLegendQueryBaseStore();
44
+ const params = useParams<IngestQueryCreatorPathParams>();
45
+
46
+ const gav = guaranteeNonNullable(
47
+ params[INGEST_QUERY_CREATOR_ROUTE_PATTERN_TOKEN.GAV],
48
+ );
49
+ const ingestDefinitionPath = guaranteeNonNullable(
50
+ params[INGEST_QUERY_CREATOR_ROUTE_PATTERN_TOKEN.INGEST_DEFINITION_PATH],
51
+ );
52
+ const dataSet = guaranteeNonNullable(
53
+ params[INGEST_QUERY_CREATOR_ROUTE_PATTERN_TOKEN.DATA_SET],
54
+ );
55
+ const { groupId, artifactId, versionId } = parseGAVCoordinates(gav);
56
+
57
+ const store = useLocalObservable(
58
+ () =>
59
+ new IngestQueryCreatorStore(
60
+ applicationStore,
61
+ baseStore.depotServerClient,
62
+ groupId,
63
+ artifactId,
64
+ versionId,
65
+ ingestDefinitionPath,
66
+ dataSet,
67
+ ),
68
+ );
69
+
70
+ return (
71
+ <QueryEditorStoreContext.Provider value={store}>
72
+ <QueryEditor />
73
+ </QueryEditorStoreContext.Provider>
74
+ );
75
+ });
@@ -0,0 +1,148 @@
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 { useApplicationStore } from '@finos/legend-application';
18
+ import {
19
+ CogIcon,
20
+ Dialog,
21
+ Modal,
22
+ ModalBody,
23
+ ModalFooter,
24
+ ModalFooterButton,
25
+ ModalHeader,
26
+ ModalHeaderActions,
27
+ ModalTitle,
28
+ TimesIcon,
29
+ } from '@finos/legend-art';
30
+ import type { LakehouseRuntime } from '@finos/legend-graph';
31
+ import { observer } from 'mobx-react-lite';
32
+ import { useEffect, useState } from 'react';
33
+ import { LegendQueryUserDataHelper } from '../../__lib__/LegendQueryUserDataHelper.js';
34
+
35
+ /**
36
+ * Modal for editing a {@link LakehouseRuntime}'s environment and warehouse.
37
+ * Reused by both the data-product and ingest query builder setup panels.
38
+ */
39
+ export const LakehouseRuntimeConfigModal = observer(
40
+ (props: {
41
+ lakehouseRuntime: LakehouseRuntime | undefined;
42
+ open: boolean;
43
+ onClose: () => void;
44
+ darkMode: boolean;
45
+ }) => {
46
+ const { lakehouseRuntime, open, onClose, darkMode } = props;
47
+ const [env, setEnv] = useState(lakehouseRuntime?.environment ?? '');
48
+ const [warehouse, setWarehouse] = useState(
49
+ lakehouseRuntime?.warehouse ?? '',
50
+ );
51
+
52
+ // sync local state when the modal opens or the runtime changes
53
+ useEffect(() => {
54
+ if (open && lakehouseRuntime) {
55
+ setEnv(lakehouseRuntime.environment ?? '');
56
+ setWarehouse(lakehouseRuntime.warehouse ?? '');
57
+ }
58
+ }, [open, lakehouseRuntime]);
59
+
60
+ const applicationStore = useApplicationStore();
61
+
62
+ const handleApply = (): void => {
63
+ if (lakehouseRuntime) {
64
+ const newEnv = env || undefined;
65
+ const newWarehouse = warehouse || undefined;
66
+ const hasChanged =
67
+ newEnv !== lakehouseRuntime.environment ||
68
+ newWarehouse !== lakehouseRuntime.warehouse;
69
+ lakehouseRuntime.environment = newEnv;
70
+ lakehouseRuntime.warehouse = newWarehouse;
71
+ if (hasChanged) {
72
+ LegendQueryUserDataHelper.persistLakehouseUserInfo(
73
+ applicationStore.userDataService,
74
+ {
75
+ env: newEnv,
76
+ snowflakeWarehouse: newWarehouse,
77
+ },
78
+ );
79
+ }
80
+ }
81
+ onClose();
82
+ };
83
+
84
+ if (!lakehouseRuntime) {
85
+ return null;
86
+ }
87
+
88
+ return (
89
+ <Dialog onClose={onClose} open={open}>
90
+ <Modal darkMode={darkMode}>
91
+ <ModalHeader>
92
+ <ModalTitle
93
+ icon={<CogIcon />}
94
+ title="Lakehouse Runtime Configuration"
95
+ />
96
+ <ModalHeaderActions>
97
+ <button
98
+ className="modal__header__action"
99
+ tabIndex={-1}
100
+ onClick={onClose}
101
+ >
102
+ <TimesIcon />
103
+ </button>
104
+ </ModalHeaderActions>
105
+ </ModalHeader>
106
+ <ModalBody>
107
+ <div className="panel__content__form__section">
108
+ <div className="panel__content__form__section__header__label">
109
+ Environment
110
+ </div>
111
+ <input
112
+ className="panel__content__form__section__input input--dark input--small"
113
+ spellCheck={false}
114
+ value={env}
115
+ placeholder="(optional)"
116
+ onChange={(e) => setEnv(e.target.value)}
117
+ />
118
+ </div>
119
+ <div className="panel__content__form__section">
120
+ <div className="panel__content__form__section__header__label">
121
+ Warehouse
122
+ </div>
123
+ <input
124
+ className="panel__content__form__section__input input--dark input--small"
125
+ spellCheck={false}
126
+ value={warehouse}
127
+ placeholder="(optional)"
128
+ onChange={(e) => setWarehouse(e.target.value)}
129
+ />
130
+ </div>
131
+ </ModalBody>
132
+ <ModalFooter>
133
+ <ModalFooterButton
134
+ text="Apply"
135
+ onClick={handleApply}
136
+ type="primary"
137
+ />
138
+ <ModalFooterButton
139
+ text="Cancel"
140
+ onClick={onClose}
141
+ type="secondary"
142
+ />
143
+ </ModalFooter>
144
+ </Modal>
145
+ </Dialog>
146
+ );
147
+ },
148
+ );
@@ -76,8 +76,10 @@ import {
76
76
  QueryDataProductNativeExecutionContextInfo,
77
77
  QueryDataProductModelAccessExecutionContextInfo,
78
78
  QueryDataProductLakehouseExecutionContextInfo,
79
+ QueryIngestExecutionContextInfo,
79
80
  ModelAccessPointGroup,
80
81
  type DataProduct,
82
+ IngestDefinition,
81
83
  LakehouseRuntime,
82
84
  V1_DATA_PRODUCT_ELEMENT_PROTOCOL_TYPE,
83
85
  V1_DataProductArtifact,
@@ -152,6 +154,11 @@ import { generateDataSpaceQueryCreatorRoute } from '../__lib__/DSL_DataSpace_Leg
152
154
  import { hasDataSpaceInfoBeenVisited } from '../__lib__/LegendQueryUserDataSpaceHelper.js';
153
155
  import { LegendQueryDataSpaceQueryBuilderState } from './data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.js';
154
156
  import { LegendQueryDataProductQueryBuilderState } from './data-product/query-builder/LegendQueryDataProductQueryBuilderState.js';
157
+ import { IngestLegendQueryBuilderState } from './ingest/IngestLegendQueryBuilderState.js';
158
+ import {
159
+ fetchIngestEntitiesByClassifier,
160
+ swapIngestInGraph,
161
+ } from './ingest/IngestQueryGraphHelper.js';
155
162
  import { DataProductSelectorState } from './data-space/DataProductSelectorState.js';
156
163
  import {
157
164
  decorateEnvWithRealm,
@@ -317,6 +324,7 @@ export abstract class QueryEditorStore {
317
324
  showAppInfo = false;
318
325
  showDataspaceInfo = false;
319
326
  showDataProductInfo = false;
327
+ showIngestInfo = false;
320
328
  enableMinialGraphForDataSpaceLoadingPerformance = true;
321
329
 
322
330
  constructor(
@@ -331,6 +339,7 @@ export abstract class QueryEditorStore {
331
339
  showAppInfo: observable,
332
340
  showDataspaceInfo: observable,
333
341
  showDataProductInfo: observable,
342
+ showIngestInfo: observable,
334
343
  queryBuilderState: observable,
335
344
  enableMinialGraphForDataSpaceLoadingPerformance: observable,
336
345
  isPerformingBlockingAction: computed,
@@ -339,6 +348,7 @@ export abstract class QueryEditorStore {
339
348
  setShowAppInfo: action,
340
349
  setShowDataspaceInfo: action,
341
350
  setShowDataProductInfo: action,
351
+ setShowIngestInfo: action,
342
352
  setEnableMinialGraphForDataSpaceLoadingPerformance: action,
343
353
  initialize: flow,
344
354
  buildGraph: flow,
@@ -453,6 +463,10 @@ export abstract class QueryEditorStore {
453
463
  this.showDataProductInfo = val;
454
464
  }
455
465
 
466
+ setShowIngestInfo(val: boolean): void {
467
+ this.showIngestInfo = val;
468
+ }
469
+
456
470
  setShowRegisterServiceModal(val: boolean): void {
457
471
  this.showRegisterServiceModal = val;
458
472
  }
@@ -1926,13 +1940,64 @@ export class ExistingQueryEditorStore extends QueryEditorStore {
1926
1940
  queryInfo?.executionContext instanceof
1927
1941
  QueryDataProductModelAccessExecutionContextInfo ||
1928
1942
  queryInfo?.executionContext instanceof
1929
- QueryDataProductLakehouseExecutionContextInfo
1943
+ QueryDataProductLakehouseExecutionContextInfo ||
1944
+ queryInfo?.executionContext instanceof QueryIngestExecutionContextInfo
1930
1945
  )
1931
1946
  ) {
1932
1947
  yield flowResult(this.buildFullGraph());
1948
+ } else if (
1949
+ queryInfo?.executionContext instanceof QueryIngestExecutionContextInfo
1950
+ ) {
1951
+ // Mirror the creator-store flow: build a graph containing only the
1952
+ // referenced ingest definition. The full project entity fetch is
1953
+ // skipped, but we still list every ingest in the project so the source
1954
+ // dropdown can show them and `swapIngestDefinition` can build a
1955
+ // different one on demand.
1956
+ yield* this.buildIngestGraph(
1957
+ queryInfo.groupId,
1958
+ queryInfo.artifactId,
1959
+ queryInfo.versionId,
1960
+ queryInfo.executionContext.ingestDefinitionPath,
1961
+ );
1933
1962
  }
1934
1963
  }
1935
1964
 
1965
+ /**
1966
+ * Cached ingest entities for the existing-query flow. Populated by
1967
+ * {@link buildIngestGraph} (called from {@link buildGraph}) and consumed by
1968
+ * {@link initQueryBuildStateFromQuery} to back the source dropdown +
1969
+ * {@link IngestLegendQueryBuilderState.swapIngest} callback.
1970
+ */
1971
+ private _ingestEntitiesByPath: Map<string, Entity> = new Map();
1972
+
1973
+ private *buildIngestGraph(
1974
+ groupId: string,
1975
+ artifactId: string,
1976
+ versionId: string,
1977
+ ingestDefinitionPath: string,
1978
+ ): GeneratorFn<void> {
1979
+ yield this.graphManagerState.initializeSystem();
1980
+
1981
+ this._ingestEntitiesByPath = (yield fetchIngestEntitiesByClassifier(
1982
+ this.depotServerClient,
1983
+ groupId,
1984
+ artifactId,
1985
+ versionId,
1986
+ )) as Map<string, Entity>;
1987
+
1988
+ const target = this._ingestEntitiesByPath.get(ingestDefinitionPath);
1989
+ if (!target) {
1990
+ throw new Error(
1991
+ `Can't find ingest definition '${ingestDefinitionPath}' in project ${groupId}:${artifactId}:${versionId}`,
1992
+ );
1993
+ }
1994
+ yield swapIngestInGraph(this.graphManagerState, target, {
1995
+ groupId,
1996
+ artifactId,
1997
+ versionId,
1998
+ });
1999
+ }
2000
+
1936
2001
  override async setUpEditorState(): Promise<void> {
1937
2002
  const queryInfo = await this.graphManagerState.graphManager.getQueryInfo(
1938
2003
  this.queryId,
@@ -2191,6 +2256,71 @@ export class ExistingQueryEditorStore extends QueryEditorStore {
2191
2256
  },
2192
2257
  );
2193
2258
  return queryBuilderState;
2259
+ } else if (exec instanceof QueryIngestExecutionContextInfo) {
2260
+ // The graph was already populated by `buildIngestGraph` (above) with
2261
+ // just the referenced ingest definition. Resolve it, build the adhoc
2262
+ // lakehouse runtime, and stand up the ingest query builder state.
2263
+ const ingestDefinition = guaranteeType(
2264
+ this.graphManagerState.graph.getElement(exec.ingestDefinitionPath),
2265
+ IngestDefinition,
2266
+ `Can't find ingest definition '${exec.ingestDefinitionPath}'`,
2267
+ );
2268
+ const projectInfo = this.getProjectInfo();
2269
+ const adhocRuntime = await this.createLakehousePackageableRuntime(
2270
+ exec.ingestDefinitionPath,
2271
+ projectInfo,
2272
+ );
2273
+ this.graphManagerState.graph.addElement(adhocRuntime, '_internal_');
2274
+
2275
+ // Tracked separately from the closure on `ingestQueryBuilderState` so
2276
+ // the swap callback can capture it directly without forming a self-
2277
+ // reference (which trips the `no-unsafe-assignment` rule).
2278
+ let currentIngestPath = exec.ingestDefinitionPath;
2279
+ const swapIngest = async (path: string): Promise<IngestDefinition> => {
2280
+ // Mirror `IngestQueryCreatorStore.swapIngestDefinition`: rebuild
2281
+ // the requested ingest in place of the current one. The entity
2282
+ // cache was populated up front by `buildIngestGraph`.
2283
+ const entity = this._ingestEntitiesByPath.get(path);
2284
+ if (!entity) {
2285
+ throw new Error(
2286
+ `Can't find ingest definition '${path}' in project ${projectInfo.groupId}:${projectInfo.artifactId}:${projectInfo.versionId}`,
2287
+ );
2288
+ }
2289
+ const next = await swapIngestInGraph(this.graphManagerState, entity, {
2290
+ currentPath: currentIngestPath,
2291
+ groupId: projectInfo.groupId,
2292
+ artifactId: projectInfo.artifactId,
2293
+ versionId: projectInfo.versionId,
2294
+ });
2295
+ currentIngestPath = next.path;
2296
+ return next;
2297
+ };
2298
+
2299
+ const ingestQueryBuilderState = new IngestLegendQueryBuilderState(
2300
+ this.applicationStore,
2301
+ undefined,
2302
+ this.graphManagerState,
2303
+ QueryBuilderDataBrowserWorkflow.INSTANCE,
2304
+ new QueryBuilderActionConfig_QueryApplication(this),
2305
+ ingestDefinition,
2306
+ Array.from(this._ingestEntitiesByPath.keys()),
2307
+ swapIngest,
2308
+ adhocRuntime,
2309
+ projectInfo,
2310
+ this.applicationStore.config.options.queryBuilderConfig,
2311
+ {
2312
+ groupId: projectInfo.groupId,
2313
+ artifactId: projectInfo.artifactId,
2314
+ versionId: projectInfo.versionId,
2315
+ queryId: queryInfo.id,
2316
+ },
2317
+ );
2318
+ await ingestQueryBuilderState.changeAccessorOwner(ingestDefinition);
2319
+ await ingestQueryBuilderState.changeAccessor({
2320
+ tableName: exec.dataSet,
2321
+ });
2322
+ ingestQueryBuilderState.changeSelectedRuntime(adhocRuntime);
2323
+ return ingestQueryBuilderState;
2194
2324
  }
2195
2325
  throw new UnsupportedOperationError(`Unsupported query execution context`);
2196
2326
  }