@finos/legend-application-query 13.8.28 → 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.
- package/lib/__lib__/LegendQueryNavigation.d.ts +12 -0
- package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
- package/lib/__lib__/LegendQueryNavigation.js +16 -0
- package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.js +15 -0
- package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
- package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
- package/lib/components/LegendQueryWebApplication.js +2 -1
- package/lib/components/LegendQueryWebApplication.js.map +1 -1
- package/lib/components/QueryEditor.d.ts.map +1 -1
- package/lib/components/QueryEditor.js +5 -1
- package/lib/components/QueryEditor.js.map +1 -1
- package/lib/components/data-product/LegendQueryDataProductQueryBuilder.d.ts.map +1 -1
- package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js +6 -40
- package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js.map +1 -1
- package/lib/components/ingest/IngestInfo.d.ts +32 -0
- package/lib/components/ingest/IngestInfo.d.ts.map +1 -0
- package/lib/components/ingest/IngestInfo.js +63 -0
- package/lib/components/ingest/IngestInfo.js.map +1 -0
- package/lib/components/ingest/IngestQueryBuilderSetupPanel.d.ts +18 -0
- package/lib/components/ingest/IngestQueryBuilderSetupPanel.d.ts.map +1 -0
- package/lib/components/ingest/IngestQueryBuilderSetupPanel.js +77 -0
- package/lib/components/ingest/IngestQueryBuilderSetupPanel.js.map +1 -0
- package/lib/components/ingest/IngestQueryCreator.d.ts +27 -0
- package/lib/components/ingest/IngestQueryCreator.d.ts.map +1 -0
- package/lib/components/ingest/IngestQueryCreator.js +45 -0
- package/lib/components/ingest/IngestQueryCreator.js.map +1 -0
- package/lib/components/shared/LakehouseRuntimeConfigModal.d.ts +29 -0
- package/lib/components/shared/LakehouseRuntimeConfigModal.d.ts.map +1 -0
- package/lib/components/shared/LakehouseRuntimeConfigModal.js +60 -0
- package/lib/components/shared/LakehouseRuntimeConfigModal.js.map +1 -0
- package/lib/index.css +1 -1
- package/lib/light-mode.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/QueryEditorStore.d.ts +10 -0
- package/lib/stores/QueryEditorStore.d.ts.map +1 -1
- package/lib/stores/QueryEditorStore.js +81 -2
- package/lib/stores/QueryEditorStore.js.map +1 -1
- package/lib/stores/ingest/IngestLegendQueryBuilderState.d.ts +122 -0
- package/lib/stores/ingest/IngestLegendQueryBuilderState.d.ts.map +1 -0
- package/lib/stores/ingest/IngestLegendQueryBuilderState.js +191 -0
- package/lib/stores/ingest/IngestLegendQueryBuilderState.js.map +1 -0
- package/lib/stores/ingest/IngestQueryCreatorStore.d.ts +75 -0
- package/lib/stores/ingest/IngestQueryCreatorStore.d.ts.map +1 -0
- package/lib/stores/ingest/IngestQueryCreatorStore.js +169 -0
- package/lib/stores/ingest/IngestQueryCreatorStore.js.map +1 -0
- package/lib/stores/ingest/IngestQueryGraphHelper.d.ts +58 -0
- package/lib/stores/ingest/IngestQueryGraphHelper.d.ts.map +1 -0
- package/lib/stores/ingest/IngestQueryGraphHelper.js +72 -0
- package/lib/stores/ingest/IngestQueryGraphHelper.js.map +1 -0
- package/package.json +12 -12
- package/src/__lib__/LegendQueryNavigation.ts +35 -0
- package/src/components/Core_LegendQueryApplicationPlugin.tsx +20 -0
- package/src/components/LegendQueryWebApplication.tsx +14 -0
- package/src/components/QueryEditor.tsx +12 -0
- package/src/components/data-product/LegendQueryDataProductQueryBuilder.tsx +7 -127
- package/src/components/ingest/IngestInfo.tsx +197 -0
- package/src/components/ingest/IngestQueryBuilderSetupPanel.tsx +204 -0
- package/src/components/ingest/IngestQueryCreator.tsx +75 -0
- package/src/components/shared/LakehouseRuntimeConfigModal.tsx +148 -0
- package/src/stores/QueryEditorStore.ts +131 -1
- package/src/stores/ingest/IngestLegendQueryBuilderState.ts +259 -0
- package/src/stores/ingest/IngestQueryCreatorStore.ts +262 -0
- package/src/stores/ingest/IngestQueryGraphHelper.ts +120 -0
- 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
|
}
|