@finos/legend-application-query 13.8.29 → 13.8.31

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 (76) hide show
  1. package/lib/__lib__/LegendQueryEvent.d.ts +3 -0
  2. package/lib/__lib__/LegendQueryEvent.d.ts.map +1 -1
  3. package/lib/__lib__/LegendQueryEvent.js +3 -0
  4. package/lib/__lib__/LegendQueryEvent.js.map +1 -1
  5. package/lib/__lib__/LegendQueryNavigation.d.ts +12 -0
  6. package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
  7. package/lib/__lib__/LegendQueryNavigation.js +16 -0
  8. package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
  9. package/lib/__lib__/LegendQueryTelemetryHelper.d.ts +3 -0
  10. package/lib/__lib__/LegendQueryTelemetryHelper.d.ts.map +1 -1
  11. package/lib/__lib__/LegendQueryTelemetryHelper.js +9 -0
  12. package/lib/__lib__/LegendQueryTelemetryHelper.js.map +1 -1
  13. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
  14. package/lib/components/Core_LegendQueryApplicationPlugin.js +15 -0
  15. package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
  16. package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
  17. package/lib/components/LegendQueryWebApplication.js +2 -1
  18. package/lib/components/LegendQueryWebApplication.js.map +1 -1
  19. package/lib/components/QueryEditor.d.ts.map +1 -1
  20. package/lib/components/QueryEditor.js +12 -2
  21. package/lib/components/QueryEditor.js.map +1 -1
  22. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.d.ts.map +1 -1
  23. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js +6 -40
  24. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js.map +1 -1
  25. package/lib/components/ingest/IngestInfo.d.ts +32 -0
  26. package/lib/components/ingest/IngestInfo.d.ts.map +1 -0
  27. package/lib/components/ingest/IngestInfo.js +63 -0
  28. package/lib/components/ingest/IngestInfo.js.map +1 -0
  29. package/lib/components/ingest/IngestQueryBuilderSetupPanel.d.ts +18 -0
  30. package/lib/components/ingest/IngestQueryBuilderSetupPanel.d.ts.map +1 -0
  31. package/lib/components/ingest/IngestQueryBuilderSetupPanel.js +77 -0
  32. package/lib/components/ingest/IngestQueryBuilderSetupPanel.js.map +1 -0
  33. package/lib/components/ingest/IngestQueryCreator.d.ts +27 -0
  34. package/lib/components/ingest/IngestQueryCreator.d.ts.map +1 -0
  35. package/lib/components/ingest/IngestQueryCreator.js +45 -0
  36. package/lib/components/ingest/IngestQueryCreator.js.map +1 -0
  37. package/lib/components/shared/LakehouseRuntimeConfigModal.d.ts +29 -0
  38. package/lib/components/shared/LakehouseRuntimeConfigModal.d.ts.map +1 -0
  39. package/lib/components/shared/LakehouseRuntimeConfigModal.js +60 -0
  40. package/lib/components/shared/LakehouseRuntimeConfigModal.js.map +1 -0
  41. package/lib/index.css +1 -1
  42. package/lib/light-mode.css +1 -1
  43. package/lib/package.json +1 -1
  44. package/lib/stores/QueryEditorStore.d.ts +10 -0
  45. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  46. package/lib/stores/QueryEditorStore.js +81 -2
  47. package/lib/stores/QueryEditorStore.js.map +1 -1
  48. package/lib/stores/ingest/IngestLegendQueryBuilderState.d.ts +122 -0
  49. package/lib/stores/ingest/IngestLegendQueryBuilderState.d.ts.map +1 -0
  50. package/lib/stores/ingest/IngestLegendQueryBuilderState.js +191 -0
  51. package/lib/stores/ingest/IngestLegendQueryBuilderState.js.map +1 -0
  52. package/lib/stores/ingest/IngestQueryCreatorStore.d.ts +75 -0
  53. package/lib/stores/ingest/IngestQueryCreatorStore.d.ts.map +1 -0
  54. package/lib/stores/ingest/IngestQueryCreatorStore.js +169 -0
  55. package/lib/stores/ingest/IngestQueryCreatorStore.js.map +1 -0
  56. package/lib/stores/ingest/IngestQueryGraphHelper.d.ts +58 -0
  57. package/lib/stores/ingest/IngestQueryGraphHelper.d.ts.map +1 -0
  58. package/lib/stores/ingest/IngestQueryGraphHelper.js +72 -0
  59. package/lib/stores/ingest/IngestQueryGraphHelper.js.map +1 -0
  60. package/package.json +13 -13
  61. package/src/__lib__/LegendQueryEvent.ts +3 -0
  62. package/src/__lib__/LegendQueryNavigation.ts +35 -0
  63. package/src/__lib__/LegendQueryTelemetryHelper.ts +15 -0
  64. package/src/components/Core_LegendQueryApplicationPlugin.tsx +20 -0
  65. package/src/components/LegendQueryWebApplication.tsx +14 -0
  66. package/src/components/QueryEditor.tsx +25 -1
  67. package/src/components/data-product/LegendQueryDataProductQueryBuilder.tsx +7 -127
  68. package/src/components/ingest/IngestInfo.tsx +197 -0
  69. package/src/components/ingest/IngestQueryBuilderSetupPanel.tsx +204 -0
  70. package/src/components/ingest/IngestQueryCreator.tsx +75 -0
  71. package/src/components/shared/LakehouseRuntimeConfigModal.tsx +148 -0
  72. package/src/stores/QueryEditorStore.ts +131 -1
  73. package/src/stores/ingest/IngestLegendQueryBuilderState.ts +259 -0
  74. package/src/stores/ingest/IngestQueryCreatorStore.ts +262 -0
  75. package/src/stores/ingest/IngestQueryGraphHelper.ts +120 -0
  76. package/tsconfig.json +7 -0
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ Dialog,
19
+ Modal,
20
+ ModalTitle,
21
+ Panel,
22
+ PanelFullContent,
23
+ } from '@finos/legend-art';
24
+ import {
25
+ LATEST_VERSION_ALIAS,
26
+ StoreProjectData,
27
+ VersionedProjectData,
28
+ } from '@finos/legend-server-depot';
29
+ import { observer } from 'mobx-react-lite';
30
+ import { flowResult } from 'mobx';
31
+ import { assertErrorThrown } from '@finos/legend-shared';
32
+ import { LakehouseRuntime } from '@finos/legend-graph';
33
+ import type { QueryEditorStore } from '../../stores/QueryEditorStore.js';
34
+ import type { IngestLegendQueryBuilderState } from '../../stores/ingest/IngestLegendQueryBuilderState.js';
35
+ import { EXTERNAL_APPLICATION_NAVIGATION__generateStudioSDLCProjectViewUrl } from '../../__lib__/LegendQueryNavigation.js';
36
+
37
+ /**
38
+ * "About Ingest" info modal, mirroring `QueryEditorDataProductInfoModal`.
39
+ * Surfaces the project GAV, the ingest name + currently selected data set,
40
+ * the adhoc lakehouse runtime (environment + warehouse), and a link to the
41
+ * ingest definition's configuration in Studio.
42
+ */
43
+ export const QueryEditorIngestInfoModal = observer(
44
+ (props: {
45
+ editorStore: QueryEditorStore;
46
+ queryBuilderState: IngestLegendQueryBuilderState;
47
+ open: boolean;
48
+ closeModal: () => void;
49
+ }) => {
50
+ const { editorStore, queryBuilderState, open, closeModal } = props;
51
+ const projectInfo = editorStore.getProjectInfo();
52
+ const ingestDefinition = queryBuilderState.ingestDefinition;
53
+ const lakehouseRuntime = queryBuilderState.lakehouseRuntime;
54
+
55
+ /**
56
+ * Open the given element path (or the project root if `undefined`) in
57
+ * Studio's SDLC project view. Mirrors `DataProductInfo.visitElement`.
58
+ */
59
+ const visitElement = async (path: string | undefined): Promise<void> => {
60
+ try {
61
+ if (projectInfo) {
62
+ const project = StoreProjectData.serialization.fromJson(
63
+ await editorStore.depotServerClient.getProject(
64
+ projectInfo.groupId,
65
+ projectInfo.artifactId,
66
+ ),
67
+ );
68
+ const versionId =
69
+ projectInfo.versionId === LATEST_VERSION_ALIAS
70
+ ? VersionedProjectData.serialization.fromJson(
71
+ await editorStore.depotServerClient.getLatestVersion(
72
+ projectInfo.groupId,
73
+ projectInfo.artifactId,
74
+ ),
75
+ ).versionId
76
+ : projectInfo.versionId;
77
+ editorStore.applicationStore.navigationService.navigator.visitAddress(
78
+ EXTERNAL_APPLICATION_NAVIGATION__generateStudioSDLCProjectViewUrl(
79
+ editorStore.applicationStore.config.studioApplicationUrl,
80
+ project.projectId,
81
+ versionId,
82
+ path,
83
+ ),
84
+ );
85
+ }
86
+ } catch (error) {
87
+ assertErrorThrown(error);
88
+ editorStore.applicationStore.notificationService.notifyError(
89
+ path
90
+ ? `Can't visit element of path: '${path}'`
91
+ : `Can't visit project`,
92
+ );
93
+ }
94
+ };
95
+
96
+ return (
97
+ <Dialog
98
+ open={open}
99
+ onClose={closeModal}
100
+ classes={{ container: 'dataspace-info-modal__container' }}
101
+ slotProps={{
102
+ paper: {
103
+ classes: { root: 'dataspace-info-modal__inner-container' },
104
+ },
105
+ }}
106
+ >
107
+ <Modal
108
+ darkMode={
109
+ !editorStore.applicationStore.layoutService
110
+ .TEMPORARY__isLightColorThemeEnabled
111
+ }
112
+ className="dataspace-info-modal"
113
+ >
114
+ <div className="dataspace-info-modal__header">
115
+ <ModalTitle title="About Ingest" />
116
+ </div>
117
+ <Panel>
118
+ <PanelFullContent>
119
+ {projectInfo && (
120
+ <div className="dataspace-info-modal__field">
121
+ <div className="dataspace-info-modal__field__label">
122
+ Project
123
+ </div>
124
+ <div
125
+ className="dataspace-info-modal__field__value dataspace-info-modal__field__value--linkable"
126
+ onClick={() => flowResult(visitElement(undefined))}
127
+ >
128
+ {`${projectInfo.groupId}:${projectInfo.artifactId}:${projectInfo.versionId}`}
129
+ </div>
130
+ </div>
131
+ )}
132
+ <div className="dataspace-info-modal__field">
133
+ <div className="dataspace-info-modal__field__label">Name</div>
134
+ <div className="dataspace-info-modal__field__value">
135
+ {ingestDefinition.name}
136
+ </div>
137
+ </div>
138
+ <div className="dataspace-info-modal__field">
139
+ <div className="dataspace-info-modal__field__label">Path</div>
140
+ <div className="dataspace-info-modal__field__value">
141
+ {ingestDefinition.path}
142
+ </div>
143
+ </div>
144
+ {queryBuilderState.dataSet && (
145
+ <div className="dataspace-info-modal__field">
146
+ <div className="dataspace-info-modal__field__label">
147
+ Data Set
148
+ </div>
149
+ <div className="dataspace-info-modal__field__value">
150
+ {queryBuilderState.dataSet}
151
+ </div>
152
+ </div>
153
+ )}
154
+ {lakehouseRuntime instanceof LakehouseRuntime && (
155
+ <>
156
+ {lakehouseRuntime.environment && (
157
+ <div className="dataspace-info-modal__field">
158
+ <div className="dataspace-info-modal__field__label">
159
+ Environment
160
+ </div>
161
+ <div className="dataspace-info-modal__field__value">
162
+ {lakehouseRuntime.environment}
163
+ </div>
164
+ </div>
165
+ )}
166
+ {lakehouseRuntime.warehouse && (
167
+ <div className="dataspace-info-modal__field">
168
+ <div className="dataspace-info-modal__field__label">
169
+ Warehouse
170
+ </div>
171
+ <div className="dataspace-info-modal__field__value">
172
+ {lakehouseRuntime.warehouse}
173
+ </div>
174
+ </div>
175
+ )}
176
+ </>
177
+ )}
178
+ <div className="dataspace-info-modal__field">
179
+ <div className="dataspace-info-modal__field__label">
180
+ Configuration
181
+ </div>
182
+ <div
183
+ className="dataspace-info-modal__field__value dataspace-info-modal__field__value--linkable"
184
+ onClick={() =>
185
+ flowResult(visitElement(ingestDefinition.path))
186
+ }
187
+ >
188
+ Show Ingest Configuration
189
+ </div>
190
+ </div>
191
+ </PanelFullContent>
192
+ </Panel>
193
+ </Modal>
194
+ </Dialog>
195
+ );
196
+ },
197
+ );
@@ -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
+ );