@finos/legend-application-query 12.0.9 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/lib/__lib__/LegendQueryEvent.d.ts +1 -0
  2. package/lib/__lib__/LegendQueryEvent.d.ts.map +1 -1
  3. package/lib/__lib__/LegendQueryEvent.js +1 -0
  4. package/lib/__lib__/LegendQueryEvent.js.map +1 -1
  5. package/lib/__lib__/LegendQueryTelemetryHelper.d.ts +7 -6
  6. package/lib/__lib__/LegendQueryTelemetryHelper.d.ts.map +1 -1
  7. package/lib/__lib__/LegendQueryTelemetryHelper.js +15 -12
  8. package/lib/__lib__/LegendQueryTelemetryHelper.js.map +1 -1
  9. package/lib/__lib__/LegendQueryUserDataHelper.d.ts +27 -0
  10. package/lib/__lib__/LegendQueryUserDataHelper.d.ts.map +1 -0
  11. package/lib/__lib__/LegendQueryUserDataHelper.js +63 -0
  12. package/lib/__lib__/LegendQueryUserDataHelper.js.map +1 -0
  13. package/lib/components/EditExistingQuerySetup.d.ts.map +1 -1
  14. package/lib/components/EditExistingQuerySetup.js +7 -71
  15. package/lib/components/EditExistingQuerySetup.js.map +1 -1
  16. package/lib/components/QueryEditor.d.ts.map +1 -1
  17. package/lib/components/QueryEditor.js +15 -72
  18. package/lib/components/QueryEditor.js.map +1 -1
  19. package/lib/components/QueryProductionizerSetup.d.ts.map +1 -1
  20. package/lib/components/QueryProductionizerSetup.js +6 -47
  21. package/lib/components/QueryProductionizerSetup.js.map +1 -1
  22. package/lib/index.css +2 -2
  23. package/lib/index.css.map +1 -1
  24. package/lib/package.json +1 -1
  25. package/lib/stores/EditExistingQuerySetupStore.d.ts +3 -12
  26. package/lib/stores/EditExistingQuerySetupStore.d.ts.map +1 -1
  27. package/lib/stores/EditExistingQuerySetupStore.js +27 -64
  28. package/lib/stores/EditExistingQuerySetupStore.js.map +1 -1
  29. package/lib/stores/LegendQueryApplicationPlugin.d.ts +4 -3
  30. package/lib/stores/LegendQueryApplicationPlugin.d.ts.map +1 -1
  31. package/lib/stores/LegendQueryApplicationPlugin.js.map +1 -1
  32. package/lib/stores/QueryEditorStore.d.ts +5 -18
  33. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  34. package/lib/stores/QueryEditorStore.js +34 -62
  35. package/lib/stores/QueryEditorStore.js.map +1 -1
  36. package/lib/stores/QueryProductionizerSetupStore.d.ts +4 -10
  37. package/lib/stores/QueryProductionizerSetupStore.d.ts.map +1 -1
  38. package/lib/stores/QueryProductionizerSetupStore.js +29 -62
  39. package/lib/stores/QueryProductionizerSetupStore.js.map +1 -1
  40. package/package.json +9 -9
  41. package/src/__lib__/LegendQueryEvent.ts +1 -0
  42. package/src/__lib__/LegendQueryTelemetryHelper.ts +19 -26
  43. package/src/__lib__/LegendQueryUserDataHelper.ts +92 -0
  44. package/src/components/EditExistingQuerySetup.tsx +10 -204
  45. package/src/components/QueryEditor.tsx +36 -251
  46. package/src/components/QueryProductionizerSetup.tsx +9 -124
  47. package/src/stores/EditExistingQuerySetupStore.ts +54 -87
  48. package/src/stores/LegendQueryApplicationPlugin.ts +4 -3
  49. package/src/stores/QueryEditorStore.ts +66 -73
  50. package/src/stores/QueryProductionizerSetupStore.ts +55 -84
  51. package/tsconfig.json +1 -0
@@ -15,15 +15,9 @@
15
15
  */
16
16
 
17
17
  import {
18
- type SelectComponent,
19
18
  Dialog,
20
19
  PanelLoadingIndicator,
21
20
  BlankPanelContent,
22
- clsx,
23
- SearchIcon,
24
- TimesIcon,
25
- CheckSquareIcon,
26
- SquareIcon,
27
21
  DropdownMenu,
28
22
  MenuContent,
29
23
  MenuContentItem,
@@ -37,7 +31,6 @@ import {
37
31
  ModalHeader,
38
32
  ModalBody,
39
33
  ModalFooter,
40
- ModalTitle,
41
34
  ModalFooterButton,
42
35
  ManageSearchIcon,
43
36
  LightBulbIcon,
@@ -47,21 +40,19 @@ import {
47
40
  ExclamationTriangleIcon,
48
41
  PanelListItem,
49
42
  Button,
43
+ clsx,
50
44
  } from '@finos/legend-art';
51
- import { debounce } from '@finos/legend-shared';
52
45
  import { observer } from 'mobx-react-lite';
53
- import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react';
46
+ import { Fragment, useEffect, useMemo, useRef } from 'react';
54
47
  import {
55
48
  type MappingQueryCreatorPathParams,
56
49
  type ExistingQueryEditorPathParams,
57
50
  type ServiceQueryCreatorPathParams,
58
51
  LEGEND_QUERY_QUERY_PARAM_TOKEN,
59
52
  LEGEND_QUERY_ROUTE_PATTERN_TOKEN,
60
- generateExistingQueryEditorRoute,
61
53
  generateQuerySetupRoute,
62
54
  } from '../__lib__/LegendQueryNavigation.js';
63
55
  import {
64
- type QueryEditorStore,
65
56
  QuerySaveAsState,
66
57
  createViewProjectHandler,
67
58
  createViewSDLCProjectHandler,
@@ -85,10 +76,11 @@ import { useLegendQueryApplicationStore } from './LegendQueryFrameworkProvider.j
85
76
  import {
86
77
  QueryBuilder,
87
78
  QueryBuilderNavigationBlocker,
79
+ QueryLoaderDialog,
88
80
  type QueryBuilderState,
89
81
  } from '@finos/legend-query-builder';
90
- import type { QueryEditorHelpMenuEntry } from '../stores/LegendQueryApplicationPlugin.js';
91
82
  import { QUERY_DOCUMENTATION_KEY } from '../application/LegendQueryDocumentation.js';
83
+ import { debounce } from '@finos/legend-shared';
92
84
  import { LegendQueryTelemetryHelper } from '../__lib__/LegendQueryTelemetryHelper.js';
93
85
 
94
86
  const QuerySaveAsDialogContent = observer(
@@ -201,231 +193,6 @@ const QuerySaveDialog = observer(() => {
201
193
  );
202
194
  });
203
195
 
204
- const QueryLoader = observer(
205
- (props: {
206
- editorStore: QueryEditorStore;
207
- queryBuilderState: QueryBuilderState;
208
- }) => {
209
- const { editorStore, queryBuilderState } = props;
210
- const applicationStore = useApplicationStore();
211
-
212
- const queryFinderRef = useRef<SelectComponent>(null);
213
- const searchInputRef = useRef<HTMLInputElement>(null);
214
- const [selectedQueryID, setSelectedQueryID] = useState('');
215
- const [isMineOnly, setIsMineOnly] = useState(false);
216
- const [searchText, setSearchText] = useState('');
217
-
218
- // search text
219
- const debouncedLoadQueries = useMemo(
220
- () =>
221
- debounce((input: string): void => {
222
- flowResult(editorStore.queryLoaderState.loadQueries(input)).catch(
223
- applicationStore.alertUnhandledError,
224
- );
225
- }, 500),
226
- [applicationStore, editorStore.queryLoaderState],
227
- );
228
- const onSearchTextChange: React.ChangeEventHandler<HTMLInputElement> = (
229
- event,
230
- ) => {
231
- if (event.target.value !== searchText) {
232
- setSearchText(event.target.value);
233
- debouncedLoadQueries.cancel();
234
- debouncedLoadQueries(event.target.value);
235
- }
236
- };
237
- const clearQuerySearching = (): void => {
238
- setSearchText('');
239
- debouncedLoadQueries.cancel();
240
- debouncedLoadQueries('');
241
- };
242
- const toggleShowCurrentUserQueriesOnly = (): void => {
243
- editorStore.queryLoaderState.setShowCurrentUserQueriesOnly(
244
- !editorStore.queryLoaderState.showCurrentUserQueriesOnly,
245
- );
246
- setIsMineOnly(!isMineOnly);
247
- debouncedLoadQueries.cancel();
248
- debouncedLoadQueries(searchText);
249
- };
250
-
251
- useEffect(() => {
252
- flowResult(editorStore.queryLoaderState.loadQueries('')).catch(
253
- applicationStore.alertUnhandledError,
254
- );
255
- }, [applicationStore, editorStore.queryLoaderState]);
256
-
257
- // actions
258
- const loadQuery = (): void => {
259
- if (selectedQueryID) {
260
- queryBuilderState.changeDetectionState.alertUnsavedChanges(() => {
261
- editorStore.queryLoaderState.setIsQueryLoaderOpen(false);
262
- applicationStore.navigationService.navigator.goToLocation(
263
- generateExistingQueryEditorRoute(selectedQueryID),
264
- { ignoreBlocking: true },
265
- );
266
- });
267
- }
268
- };
269
-
270
- // life-cycle
271
- const close = (): void => {
272
- editorStore.queryLoaderState.setIsQueryLoaderOpen(false);
273
- editorStore.queryLoaderState.reset();
274
- };
275
- const onEnter = (): void => queryFinderRef.current?.focus();
276
-
277
- return (
278
- <Dialog
279
- open={editorStore.queryLoaderState.isQueryLoaderOpen}
280
- onClose={close}
281
- TransitionProps={{
282
- onEnter,
283
- }}
284
- classes={{ container: 'search-modal__container' }}
285
- PaperProps={{ classes: { root: 'search-modal__inner-container' } }}
286
- >
287
- <Modal darkMode={true} className="search-modal">
288
- <ModalTitle title="Load Query" />
289
- <div className="query-editor__query-loader__filter-section">
290
- <div className="query-editor__query-loader__filter-section__section__toggler">
291
- <button
292
- className={clsx(
293
- 'query-editor__query-loader__filter-section__section__toggler__btn',
294
- {
295
- 'query-editor__query-loader__filter-section__section__toggler__btn--toggled':
296
- isMineOnly,
297
- },
298
- )}
299
- onClick={toggleShowCurrentUserQueriesOnly}
300
- tabIndex={-1}
301
- >
302
- {isMineOnly ? <CheckSquareIcon /> : <SquareIcon />}
303
- </button>
304
- <div
305
- className="query-editor__query-loader__filter-section__section__toggler__prompt"
306
- onClick={toggleShowCurrentUserQueriesOnly}
307
- >
308
- Mine Only
309
- </div>
310
- </div>
311
- </div>
312
- <div className="query-editor__query-loader__search-section">
313
- <div className="query-editor__query-loader__search-section__input__container">
314
- <input
315
- ref={searchInputRef}
316
- className={clsx(
317
- 'query-editor__query-loader__search-section__input input--dark',
318
- {
319
- 'query-editor__query-loader__search-section__input--searching':
320
- searchText,
321
- },
322
- )}
323
- onChange={onSearchTextChange}
324
- value={searchText}
325
- placeholder="Search a query by name"
326
- />
327
- {!searchText ? (
328
- <div className="query-editor__query-loader__search-section__input__search__icon">
329
- <SearchIcon />
330
- </div>
331
- ) : (
332
- <>
333
- <button
334
- className="query-editor__query-loader__search-section__input__clear-btn"
335
- tabIndex={-1}
336
- onClick={clearQuerySearching}
337
- title="Clear"
338
- >
339
- <TimesIcon />
340
- </button>
341
- </>
342
- )}
343
- </div>
344
- </div>
345
- <div className="query-editor__query-loader__body">
346
- {editorStore.queryLoaderState.loadQueriesState.hasCompleted && (
347
- <>
348
- {editorStore.queryLoaderState.queries.length > 0 && (
349
- <>
350
- <table className="table">
351
- <thead>
352
- <tr>
353
- <th className="table__cell--left">Name</th>
354
- <th className="table__cell--left">Author</th>
355
- <th className="table__cell--left">Version</th>
356
- </tr>
357
- </thead>
358
- <tbody>
359
- {editorStore.queryLoaderState.queries.map((query) => (
360
- <tr
361
- key={query.id}
362
- className={clsx(
363
- 'query-editor__query-loader__body__table__row',
364
- {
365
- 'query-editor__query-loader__body__table__row--selected':
366
- selectedQueryID === query.id,
367
- },
368
- )}
369
- onClick={(event) => setSelectedQueryID(query.id)}
370
- >
371
- <td className="table__cell--left">{query.name}</td>
372
- <td className="table__cell--left">
373
- {query.owner ?? 'anonymous'}
374
- </td>
375
- <td className="table__cell--left">
376
- {query.versionId}
377
- </td>
378
- </tr>
379
- ))}
380
- </tbody>
381
- </table>
382
- </>
383
- )}
384
- {editorStore.queryLoaderState.queries.length === 0 && (
385
- <BlankPanelContent>No query available</BlankPanelContent>
386
- )}
387
- </>
388
- )}
389
- {!editorStore.queryLoaderState.loadQueriesState.hasCompleted && (
390
- <>
391
- <PanelLoadingIndicator
392
- isLoading={
393
- !editorStore.queryLoaderState.loadQueriesState.hasCompleted
394
- }
395
- />
396
- <BlankPanelContent>Loading queries...</BlankPanelContent>
397
- </>
398
- )}
399
- </div>
400
- <div className="search-modal__actions">
401
- <button
402
- className="btn btn--dark"
403
- onClick={loadQuery}
404
- disabled={selectedQueryID === ''}
405
- >
406
- Load Query
407
- </button>
408
- <button className="btn btn--dark" onClick={close}>
409
- Close
410
- </button>
411
- </div>
412
- </Modal>
413
- </Dialog>
414
- );
415
- },
416
- );
417
-
418
- const HelpMenuContentItemRenderer = (
419
- props: QueryEditorHelpMenuEntry,
420
- ): React.ReactElement => (
421
- <MenuContentItem title={props.title ?? ''} onClick={props.onClick}>
422
- {props.icon && <MenuContentItemIcon>{props.icon}</MenuContentItemIcon>}
423
- <MenuContentItemLabel className="query-builder__sub-header__menu-content">
424
- {props.label}
425
- </MenuContentItemLabel>
426
- </MenuContentItem>
427
- );
428
-
429
196
  const QueryEditorHeaderContent = observer(
430
197
  (props: { queryBuilderState: QueryBuilderState }) => {
431
198
  const { queryBuilderState } = props;
@@ -435,7 +202,7 @@ const QueryEditorHeaderContent = observer(
435
202
 
436
203
  // actions
437
204
  const openQueryLoader = (): void => {
438
- editorStore.queryLoaderState.setIsQueryLoaderOpen(true);
205
+ editorStore.queryLoaderState.setQueryLoaderDialogOpen(true);
439
206
  };
440
207
  const viewProject = (): void => {
441
208
  LegendQueryTelemetryHelper.logEvent_QueryViewProjectLaunched(
@@ -492,9 +259,13 @@ const QueryEditorHeaderContent = observer(
492
259
  .catch(applicationStore.alertUnhandledError);
493
260
  };
494
261
 
495
- const renameQuery = applicationStore.guardUnhandledError(async () => {
496
- await renameState?.renameQuery();
497
- });
262
+ const renameQuery = (): void => {
263
+ if (renameState?.renameQuery) {
264
+ flowResult(renameState.renameQuery()).catch(
265
+ applicationStore.alertUnhandledError,
266
+ );
267
+ }
268
+ };
498
269
 
499
270
  const saveQuery = (): void => {
500
271
  queryBuilderState
@@ -583,8 +354,22 @@ const QueryEditorHeaderContent = observer(
583
354
 
584
355
  const extraHelpMenuContentItems = applicationStore.pluginManager
585
356
  .getApplicationPlugins()
586
- .flatMap((plugin) => plugin.getExtraQueryEditorHelpMenuEntries?.() ?? [])
587
- .map((item) => <>{HelpMenuContentItemRenderer(item)}</>);
357
+ .flatMap(
358
+ (plugin) =>
359
+ plugin.getExtraQueryEditorHelpMenuActionConfigurations?.() ?? [],
360
+ )
361
+ .map((item) => (
362
+ <MenuContentItem
363
+ key={item.key}
364
+ title={item.title ?? ''}
365
+ onClick={item.onClick}
366
+ >
367
+ {item.icon && <MenuContentItemIcon>{item.icon}</MenuContentItemIcon>}
368
+ <MenuContentItemLabel className="query-builder__sub-header__menu-content">
369
+ {item.label}
370
+ </MenuContentItemLabel>
371
+ </MenuContentItem>
372
+ ));
588
373
 
589
374
  return (
590
375
  <div className="query-editor__header__content">
@@ -711,17 +496,17 @@ const QueryEditorHeaderContent = observer(
711
496
  }
712
497
  >
713
498
  <div
714
- className=" query-editor__header__action__label"
499
+ className="query-editor__header__action__label"
715
500
  title="See more options"
716
501
  >
717
- Help
502
+ Help...
718
503
  </div>
719
- <CaretDownIcon />
504
+ <CaretDownIcon className="query-editor__header__action__dropdown-trigger" />
720
505
  </DropdownMenu>
721
- {editorStore.queryLoaderState.isQueryLoaderOpen && (
722
- <QueryLoader
723
- editorStore={editorStore}
724
- queryBuilderState={queryBuilderState}
506
+ {editorStore.queryLoaderState.isQueryLoaderDialogOpen && (
507
+ <QueryLoaderDialog
508
+ queryLoaderState={editorStore.queryLoaderState}
509
+ title="Load query"
725
510
  />
726
511
  )}
727
512
  <button
@@ -776,7 +561,7 @@ const QueryEditorHeaderContent = observer(
776
561
  >
777
562
  More Actions...
778
563
  </div>
779
- <CaretDownIcon />
564
+ <CaretDownIcon className="query-editor__header__action__dropdown-trigger" />
780
565
  </DropdownMenu>
781
566
 
782
567
  {editorStore.saveAsState && <QuerySaveDialog />}
@@ -14,20 +14,10 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import {
18
- ArrowLeftIcon,
19
- ArrowRightIcon,
20
- BlankPanelContent,
21
- clsx,
22
- CustomSelectorInput,
23
- PanelLoadingIndicator,
24
- SearchIcon,
25
- type SelectComponent,
26
- } from '@finos/legend-art';
27
- import { debounce, guaranteeType } from '@finos/legend-shared';
28
- import { flowResult } from 'mobx';
17
+ import { ArrowLeftIcon } from '@finos/legend-art';
18
+ import { guaranteeType } from '@finos/legend-shared';
29
19
  import { observer, useLocalObservable } from 'mobx-react-lite';
30
- import { useContext, useEffect, useMemo, useRef, useState } from 'react';
20
+ import { useContext } from 'react';
31
21
  import { useApplicationStore } from '@finos/legend-application';
32
22
  import {
33
23
  useLegendQueryApplicationStore,
@@ -35,15 +25,8 @@ import {
35
25
  } from './LegendQueryFrameworkProvider.js';
36
26
  import { QueryProductionizerSetupStore } from '../stores/QueryProductionizerSetupStore.js';
37
27
  import { BaseQuerySetup, BaseQuerySetupStoreContext } from './QuerySetup.js';
38
- import {
39
- buildQueryOption,
40
- type QueryOption,
41
- } from '@finos/legend-query-builder';
42
28
  import { generateQuerySetupRoute } from '../__lib__/LegendQueryNavigation.js';
43
- import {
44
- CODE_EDITOR_LANGUAGE,
45
- CodeEditor,
46
- } from '@finos/legend-lego/code-editor';
29
+ import { QueryLoader } from '@finos/legend-query-builder';
47
30
 
48
31
  const QueryProductionizerSetupStoreProvider: React.FC<{
49
32
  children: React.ReactNode;
@@ -74,8 +57,6 @@ const useQueryProductionizerSetupStore = (): QueryProductionizerSetupStore =>
74
57
  const QueryProductionizerSetupContent = observer(() => {
75
58
  const applicationStore = useApplicationStore();
76
59
  const setupStore = useQueryProductionizerSetupStore();
77
- const querySearchRef = useRef<SelectComponent>(null);
78
- const [searchText, setSearchText] = useState('');
79
60
 
80
61
  // actions
81
62
  const back = (): void => {
@@ -83,53 +64,6 @@ const QueryProductionizerSetupContent = observer(() => {
83
64
  generateQuerySetupRoute(),
84
65
  );
85
66
  };
86
- const next = (): void => {
87
- if (setupStore.currentQuery) {
88
- setupStore
89
- .loadQueryProductionizer()
90
- .catch(applicationStore.alertUnhandledError);
91
- }
92
- };
93
- const canProceed = setupStore.currentQuery;
94
-
95
- // query
96
- const queryOptions = setupStore.queries.map(buildQueryOption);
97
- const selectedQueryOption = setupStore.currentQuery
98
- ? buildQueryOption(setupStore.currentQuery)
99
- : null;
100
- const onQueryOptionChange = (option: QueryOption | null): void => {
101
- if (option?.value !== setupStore.currentQuery) {
102
- setupStore.setCurrentQuery(option?.value.id);
103
- }
104
- };
105
-
106
- // search text
107
- const debouncedLoadQueries = useMemo(
108
- () =>
109
- debounce((input: string): void => {
110
- flowResult(setupStore.loadQueries(input)).catch(
111
- applicationStore.alertUnhandledError,
112
- );
113
- }, 500),
114
- [applicationStore, setupStore],
115
- );
116
- const onSearchTextChange = (value: string): void => {
117
- if (value !== searchText) {
118
- setSearchText(value);
119
- debouncedLoadQueries.cancel();
120
- debouncedLoadQueries(value);
121
- }
122
- };
123
-
124
- useEffect(() => {
125
- flowResult(setupStore.loadQueries('')).catch(
126
- applicationStore.alertUnhandledError,
127
- );
128
- }, [setupStore, applicationStore]);
129
-
130
- useEffect(() => {
131
- querySearchRef.current?.focus();
132
- }, []);
133
67
 
134
68
  return (
135
69
  <div className="query-setup__wizard query-setup__productionize-query">
@@ -144,61 +78,12 @@ const QueryProductionizerSetupContent = observer(() => {
144
78
  <div className="query-setup__wizard__header__title">
145
79
  Productionizing an existing query...
146
80
  </div>
147
- <button
148
- className={clsx('query-setup__wizard__header__btn', {
149
- 'query-setup__wizard__header__btn--ready': canProceed,
150
- })}
151
- onClick={next}
152
- disabled={!canProceed}
153
- title="Productionize query"
154
- >
155
- <ArrowRightIcon />
156
- </button>
157
81
  </div>
158
- <div className="query-setup__wizard__content">
159
- <div className="query-setup__wizard__group query-setup__wizard__group--inline">
160
- <div className="query-setup__wizard__group__title">
161
- <SearchIcon />
162
- </div>
163
- <CustomSelectorInput
164
- ref={querySearchRef}
165
- className="query-setup__wizard__selector"
166
- options={queryOptions}
167
- isLoading={setupStore.loadQueriesState.isInProgress}
168
- onInputChange={onSearchTextChange}
169
- inputValue={searchText}
170
- onChange={onQueryOptionChange}
171
- value={selectedQueryOption}
172
- placeholder="Search for query by name..."
173
- isClearable={true}
174
- escapeClearsValue={true}
175
- darkMode={true}
176
- />
177
- </div>
178
- <div className="query-setup__productionize-query__preview">
179
- <PanelLoadingIndicator
180
- isLoading={setupStore.loadQueryState.isInProgress}
181
- />
182
- {setupStore.currentQuery && (
183
- <>
184
- {!setupStore.currentQueryInfo && (
185
- <BlankPanelContent>{`Can't preview query`}</BlankPanelContent>
186
- )}
187
- {setupStore.currentQueryInfo && (
188
- <CodeEditor
189
- inputValue={setupStore.currentQueryInfo.content}
190
- isReadOnly={true}
191
- language={CODE_EDITOR_LANGUAGE.PURE}
192
- showMiniMap={false}
193
- hideGutter={true}
194
- />
195
- )}
196
- </>
197
- )}
198
- {!setupStore.currentQuery && (
199
- <BlankPanelContent>No query to preview</BlankPanelContent>
200
- )}
201
- </div>
82
+ <div className="query-setup__productionize-query__content">
83
+ <QueryLoader
84
+ queryLoaderState={setupStore.queryLoaderState}
85
+ loadActionLabel="productionize query"
86
+ />
202
87
  </div>
203
88
  </div>
204
89
  );