@finos/legend-application-query 7.0.1 → 8.1.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 (83) hide show
  1. package/lib/LegendQueryAppEvent.d.ts +1 -1
  2. package/lib/LegendQueryAppEvent.d.ts.map +1 -1
  3. package/lib/LegendQueryAppEvent.js +1 -1
  4. package/lib/LegendQueryAppEvent.js.map +1 -1
  5. package/lib/application/LegendQuery.d.ts.map +1 -1
  6. package/lib/application/LegendQuery.js +1 -1
  7. package/lib/application/LegendQuery.js.map +1 -1
  8. package/lib/application/LegendQueryApplicationConfig.d.ts +6 -7
  9. package/lib/application/LegendQueryApplicationConfig.d.ts.map +1 -1
  10. package/lib/application/LegendQueryApplicationConfig.js +9 -4
  11. package/lib/application/LegendQueryApplicationConfig.js.map +1 -1
  12. package/lib/components/LegendQueryApplication.d.ts +1 -2
  13. package/lib/components/LegendQueryApplication.d.ts.map +1 -1
  14. package/lib/components/LegendQueryApplication.js +2 -3
  15. package/lib/components/LegendQueryApplication.js.map +1 -1
  16. package/lib/components/LegendQueryBaseStoreProvider.d.ts +1 -3
  17. package/lib/components/LegendQueryBaseStoreProvider.d.ts.map +1 -1
  18. package/lib/components/LegendQueryBaseStoreProvider.js +2 -2
  19. package/lib/components/LegendQueryBaseStoreProvider.js.map +1 -1
  20. package/lib/components/QueryEditor.d.ts +1 -0
  21. package/lib/components/QueryEditor.d.ts.map +1 -1
  22. package/lib/components/QueryEditor.js +42 -28
  23. package/lib/components/QueryEditor.js.map +1 -1
  24. package/lib/components/QueryEditorComponentTestUtils.d.ts.map +1 -1
  25. package/lib/components/QueryEditorComponentTestUtils.js +2 -2
  26. package/lib/components/QueryEditorComponentTestUtils.js.map +1 -1
  27. package/lib/components/QueryEditorStoreProvider.d.ts.map +1 -1
  28. package/lib/components/QueryEditorStoreProvider.js +6 -8
  29. package/lib/components/QueryEditorStoreProvider.js.map +1 -1
  30. package/lib/components/QuerySetup.d.ts +6 -0
  31. package/lib/components/QuerySetup.d.ts.map +1 -1
  32. package/lib/components/QuerySetup.js +152 -34
  33. package/lib/components/QuerySetup.js.map +1 -1
  34. package/lib/components/QuerySetupStoreProvider.d.ts.map +1 -1
  35. package/lib/components/QuerySetupStoreProvider.js +2 -3
  36. package/lib/components/QuerySetupStoreProvider.js.map +1 -1
  37. package/lib/index.css +2 -2
  38. package/lib/index.css.map +1 -1
  39. package/lib/index.d.ts +1 -1
  40. package/lib/index.d.ts.map +1 -1
  41. package/lib/index.js +1 -1
  42. package/lib/index.js.map +1 -1
  43. package/lib/package.json +9 -9
  44. package/lib/stores/LegendQueryApplicationPlugin.d.ts +10 -2
  45. package/lib/stores/LegendQueryApplicationPlugin.d.ts.map +1 -1
  46. package/lib/stores/LegendQueryApplicationPlugin.js.map +1 -1
  47. package/lib/stores/LegendQueryBaseStore.d.ts +2 -3
  48. package/lib/stores/LegendQueryBaseStore.d.ts.map +1 -1
  49. package/lib/stores/LegendQueryBaseStore.js +2 -2
  50. package/lib/stores/LegendQueryBaseStore.js.map +1 -1
  51. package/lib/stores/LegendQueryRouter.d.ts +16 -1
  52. package/lib/stores/LegendQueryRouter.d.ts.map +1 -1
  53. package/lib/stores/LegendQueryRouter.js +17 -2
  54. package/lib/stores/LegendQueryRouter.js.map +1 -1
  55. package/lib/stores/QueryEditorStore.d.ts +15 -12
  56. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  57. package/lib/stores/QueryEditorStore.js +24 -19
  58. package/lib/stores/QueryEditorStore.js.map +1 -1
  59. package/lib/stores/QueryEditorStoreTestUtils.d.ts.map +1 -1
  60. package/lib/stores/QueryEditorStoreTestUtils.js +1 -0
  61. package/lib/stores/QueryEditorStoreTestUtils.js.map +1 -1
  62. package/lib/stores/QuerySetupStore.d.ts +35 -9
  63. package/lib/stores/QuerySetupStore.d.ts.map +1 -1
  64. package/lib/stores/QuerySetupStore.js +188 -17
  65. package/lib/stores/QuerySetupStore.js.map +1 -1
  66. package/package.json +17 -17
  67. package/src/LegendQueryAppEvent.ts +1 -1
  68. package/src/application/LegendQuery.tsx +1 -4
  69. package/src/application/LegendQueryApplicationConfig.ts +30 -10
  70. package/src/components/LegendQueryApplication.tsx +3 -9
  71. package/src/components/LegendQueryBaseStoreProvider.tsx +4 -14
  72. package/src/components/QueryEditor.tsx +77 -61
  73. package/src/components/QueryEditorComponentTestUtils.tsx +1 -6
  74. package/src/components/QueryEditorStoreProvider.tsx +3 -14
  75. package/src/components/QuerySetup.tsx +411 -50
  76. package/src/components/QuerySetupStoreProvider.tsx +2 -11
  77. package/src/index.ts +1 -0
  78. package/src/stores/LegendQueryApplicationPlugin.ts +18 -2
  79. package/src/stores/LegendQueryBaseStore.ts +2 -4
  80. package/src/stores/LegendQueryRouter.ts +35 -2
  81. package/src/stores/QueryEditorStore.ts +34 -30
  82. package/src/stores/QueryEditorStoreTestUtils.ts +1 -0
  83. package/src/stores/QuerySetupStore.ts +275 -20
@@ -22,12 +22,14 @@ import {
22
22
  clsx,
23
23
  CustomSelectorInput,
24
24
  PanelLoadingIndicator,
25
- PencilIcon,
26
25
  PlusIcon,
27
26
  RobotIcon,
28
27
  SearchIcon,
29
28
  UserIcon,
30
29
  QuestionCircleIcon,
30
+ DroidIcon,
31
+ ManageSearchIcon,
32
+ ArrowCirceUpIcon,
31
33
  } from '@finos/legend-art';
32
34
  import {
33
35
  debounce,
@@ -47,7 +49,10 @@ import {
47
49
  type ServiceExecutionOption,
48
50
  CreateMappingQuerySetupState,
49
51
  EditExistingQuerySetupState,
50
- LoadServiceQuerySetupState,
52
+ CloneServiceQuerySetupState,
53
+ UpdateExistingServiceQuerySetupState,
54
+ LoadProjectServiceQuerySetupState,
55
+ QueryProductionizationSetupState,
51
56
  } from '../stores/QuerySetupStore.js';
52
57
  import {
53
58
  useQuerySetupStore,
@@ -57,24 +62,24 @@ import {
57
62
  type ProjectData,
58
63
  LATEST_VERSION_ALIAS,
59
64
  SNAPSHOT_VERSION_ALIAS,
60
- compareSemVerVersions,
61
65
  } from '@finos/legend-server-depot';
62
- import type {
63
- LightQuery,
64
- Mapping,
65
- PackageableRuntime,
66
- } from '@finos/legend-graph';
66
+ import { compareSemVerVersions } from '@finos/legend-storage';
67
+ import type { Mapping, PackageableRuntime } from '@finos/legend-graph';
67
68
  import {
68
69
  type PackageableElementOption,
69
70
  useApplicationStore,
70
71
  buildElementOption,
72
+ EDITOR_LANGUAGE,
73
+ TextInputEditor,
71
74
  } from '@finos/legend-application';
72
-
73
- type QueryOption = { label: string; value: LightQuery };
74
- const buildQueryOption = (query: LightQuery): QueryOption => ({
75
- label: query.name,
76
- value: query,
77
- });
75
+ import {
76
+ type ServiceOption,
77
+ type QueryOption,
78
+ buildServiceOption,
79
+ formatServiceOptionLabel,
80
+ buildQueryOption,
81
+ } from '@finos/legend-query-builder';
82
+ import { useLegendQueryApplicationStore } from './LegendQueryBaseStoreProvider.js';
78
83
 
79
84
  const EditExistingQuerySetup = observer(
80
85
  (props: { querySetupState: EditExistingQuerySetupState }) => {
@@ -83,9 +88,10 @@ const EditExistingQuerySetup = observer(
83
88
  const setupStore = useQuerySetupStore();
84
89
  const querySearchRef = useRef<SelectComponent>(null);
85
90
  const [searchText, setSearchText] = useState('');
91
+
92
+ // actions
86
93
  const back = (): void => {
87
94
  setupStore.setSetupState(undefined);
88
- querySetupState.setCurrentQuery(undefined);
89
95
  };
90
96
  const next = (): void => {
91
97
  if (querySetupState.currentQuery) {
@@ -93,20 +99,9 @@ const EditExistingQuerySetup = observer(
93
99
  generateExistingQueryEditorRoute(querySetupState.currentQuery.id),
94
100
  );
95
101
  }
96
- setupStore.setSetupState(undefined);
97
102
  };
98
103
  const canProceed = querySetupState.currentQuery;
99
104
 
100
- // show current user queries only
101
- const toggleShowCurrentUserQueriesOnly = (): void => {
102
- querySetupState.setShowCurrentUserQueriesOnly(
103
- !querySetupState.showCurrentUserQueriesOnly,
104
- );
105
- flowResult(querySetupState.loadQueries(searchText)).catch(
106
- applicationStore.alertUnhandledError,
107
- );
108
- };
109
-
110
105
  // query
111
106
  const queryOptions = querySetupState.queries.map(buildQueryOption);
112
107
  const selectedQueryOption = querySetupState.currentQuery
@@ -137,7 +132,10 @@ const EditExistingQuerySetup = observer(
137
132
  }
138
133
  return (
139
134
  <div className="query-setup__existing-query__query-option">
140
- <div className="query-setup__existing-query__query-option__label">
135
+ <div
136
+ className="query-setup__existing-query__query-option__label"
137
+ title={option.label}
138
+ >
141
139
  {option.label}
142
140
  </div>
143
141
  {querySetupState.showCurrentUserQueriesOnly && (
@@ -185,6 +183,15 @@ const EditExistingQuerySetup = observer(
185
183
  }
186
184
  };
187
185
 
186
+ // show current user queries only
187
+ const toggleShowCurrentUserQueriesOnly = (): void => {
188
+ querySetupState.setShowCurrentUserQueriesOnly(
189
+ !querySetupState.showCurrentUserQueriesOnly,
190
+ );
191
+ debouncedLoadQueries.cancel();
192
+ debouncedLoadQueries(searchText);
193
+ };
194
+
188
195
  useEffect(() => {
189
196
  flowResult(querySetupState.loadQueries('')).catch(
190
197
  applicationStore.alertUnhandledError,
@@ -214,7 +221,7 @@ const EditExistingQuerySetup = observer(
214
221
  })}
215
222
  onClick={next}
216
223
  disabled={!canProceed}
217
- title="Proceed"
224
+ title="Edit query"
218
225
  >
219
226
  <ArrowRightIcon />
220
227
  </button>
@@ -255,6 +262,249 @@ const EditExistingQuerySetup = observer(
255
262
  </button>
256
263
  </div>
257
264
  </div>
265
+ <div className="query-setup__existing-query__preview">
266
+ <PanelLoadingIndicator
267
+ isLoading={querySetupState.loadQueryState.isInProgress}
268
+ />
269
+ {querySetupState.currentQuery && (
270
+ <>
271
+ {!querySetupState.currentQueryInfo && (
272
+ <BlankPanelContent>{`Can't preview query`}</BlankPanelContent>
273
+ )}
274
+ {querySetupState.currentQueryInfo && (
275
+ <TextInputEditor
276
+ inputValue={querySetupState.currentQueryInfo.content}
277
+ isReadOnly={true}
278
+ language={EDITOR_LANGUAGE.PURE}
279
+ showMiniMap={false}
280
+ hideGutter={true}
281
+ />
282
+ )}
283
+ </>
284
+ )}
285
+ {!querySetupState.currentQuery && (
286
+ <BlankPanelContent>No query to preview</BlankPanelContent>
287
+ )}
288
+ </div>
289
+ </div>
290
+ </div>
291
+ );
292
+ },
293
+ );
294
+
295
+ const QueryProductionizationSetup = observer(
296
+ (props: { querySetupState: QueryProductionizationSetupState }) => {
297
+ const { querySetupState } = props;
298
+ const applicationStore = useApplicationStore();
299
+ const setupStore = useQuerySetupStore();
300
+ const querySearchRef = useRef<SelectComponent>(null);
301
+ const [searchText, setSearchText] = useState('');
302
+
303
+ // actions
304
+ const back = (): void => {
305
+ setupStore.setSetupState(undefined);
306
+ };
307
+ const next = (): void => {
308
+ if (querySetupState.currentQuery) {
309
+ querySetupState
310
+ .loadQueryProductionizer()
311
+ .catch(applicationStore.alertUnhandledError);
312
+ }
313
+ };
314
+ const canProceed = querySetupState.currentQuery;
315
+
316
+ // query
317
+ const queryOptions = querySetupState.queries.map(buildQueryOption);
318
+ const selectedQueryOption = querySetupState.currentQuery
319
+ ? buildQueryOption(querySetupState.currentQuery)
320
+ : null;
321
+ const onQueryOptionChange = (option: QueryOption | null): void => {
322
+ if (option?.value !== querySetupState.currentQuery) {
323
+ querySetupState.setCurrentQuery(option?.value.id);
324
+ }
325
+ };
326
+
327
+ // search text
328
+ const debouncedLoadQueries = useMemo(
329
+ () =>
330
+ debounce((input: string): void => {
331
+ flowResult(querySetupState.loadQueries(input)).catch(
332
+ applicationStore.alertUnhandledError,
333
+ );
334
+ }, 500),
335
+ [applicationStore, querySetupState],
336
+ );
337
+ const onSearchTextChange = (value: string): void => {
338
+ if (value !== searchText) {
339
+ setSearchText(value);
340
+ debouncedLoadQueries.cancel();
341
+ debouncedLoadQueries(value);
342
+ }
343
+ };
344
+
345
+ useEffect(() => {
346
+ flowResult(querySetupState.loadQueries('')).catch(
347
+ applicationStore.alertUnhandledError,
348
+ );
349
+ }, [querySetupState, applicationStore]);
350
+
351
+ useEffect(() => {
352
+ querySearchRef.current?.focus();
353
+ }, []);
354
+
355
+ return (
356
+ <div className="query-setup__wizard query-setup__productionize-query">
357
+ <div className="query-setup__wizard__header query-setup__productionize-query__header">
358
+ <button
359
+ className="query-setup__wizard__header__btn"
360
+ onClick={back}
361
+ title="Back to Main Menu"
362
+ >
363
+ <ArrowLeftIcon />
364
+ </button>
365
+ <div className="query-setup__wizard__header__title">
366
+ Productionizing an existing query...
367
+ </div>
368
+ <button
369
+ className={clsx('query-setup__wizard__header__btn', {
370
+ 'query-setup__wizard__header__btn--ready': canProceed,
371
+ })}
372
+ onClick={next}
373
+ disabled={!canProceed}
374
+ title="Productionize query"
375
+ >
376
+ <ArrowRightIcon />
377
+ </button>
378
+ </div>
379
+ <div className="query-setup__wizard__content">
380
+ <div className="query-setup__wizard__group query-setup__wizard__group--inline">
381
+ <div className="query-setup__wizard__group__title">
382
+ <SearchIcon />
383
+ </div>
384
+ <CustomSelectorInput
385
+ ref={querySearchRef}
386
+ className="query-setup__wizard__selector"
387
+ options={queryOptions}
388
+ isLoading={querySetupState.loadQueriesState.isInProgress}
389
+ onInputChange={onSearchTextChange}
390
+ inputValue={searchText}
391
+ onChange={onQueryOptionChange}
392
+ value={selectedQueryOption}
393
+ placeholder="Search for query by name..."
394
+ isClearable={true}
395
+ escapeClearsValue={true}
396
+ darkMode={true}
397
+ />
398
+ </div>
399
+ <div className="query-setup__productionize-query__preview">
400
+ <PanelLoadingIndicator
401
+ isLoading={querySetupState.loadQueryState.isInProgress}
402
+ />
403
+ {querySetupState.currentQuery && (
404
+ <>
405
+ {!querySetupState.currentQueryInfo && (
406
+ <BlankPanelContent>{`Can't preview query`}</BlankPanelContent>
407
+ )}
408
+ {querySetupState.currentQueryInfo && (
409
+ <TextInputEditor
410
+ inputValue={querySetupState.currentQueryInfo.content}
411
+ isReadOnly={true}
412
+ language={EDITOR_LANGUAGE.PURE}
413
+ showMiniMap={false}
414
+ hideGutter={true}
415
+ />
416
+ )}
417
+ </>
418
+ )}
419
+ {!querySetupState.currentQuery && (
420
+ <BlankPanelContent>No query to preview</BlankPanelContent>
421
+ )}
422
+ </div>
423
+ </div>
424
+ </div>
425
+ );
426
+ },
427
+ );
428
+
429
+ export const UpdateExistingServiceQuerySetup = observer(
430
+ (props: { querySetupState: UpdateExistingServiceQuerySetupState }) => {
431
+ const { querySetupState } = props;
432
+ const applicationStore = useLegendQueryApplicationStore();
433
+ const setupStore = useQuerySetupStore();
434
+ const serviceSearchRef = useRef<SelectComponent>(null);
435
+ const [searchText, setSearchText] = useState('');
436
+
437
+ const back = (): void => {
438
+ setupStore.setSetupState(undefined);
439
+ };
440
+
441
+ const serviceOptions = querySetupState.services.map(buildServiceOption);
442
+ const onServiceOptionChange = (option: ServiceOption): void => {
443
+ querySetupState
444
+ .loadServiceUpdater(option.value)
445
+ .catch(applicationStore.alertUnhandledError);
446
+ };
447
+
448
+ // search text
449
+ const debouncedLoadServices = useMemo(
450
+ () =>
451
+ debounce((input: string): void => {
452
+ flowResult(querySetupState.loadServices(input)).catch(
453
+ applicationStore.alertUnhandledError,
454
+ );
455
+ }, 500),
456
+ [applicationStore, querySetupState],
457
+ );
458
+ const onSearchTextChange = (value: string): void => {
459
+ if (value !== searchText) {
460
+ setSearchText(value);
461
+ debouncedLoadServices.cancel();
462
+ debouncedLoadServices(value);
463
+ }
464
+ };
465
+
466
+ useEffect(() => {
467
+ flowResult(querySetupState.loadServices('')).catch(
468
+ applicationStore.alertUnhandledError,
469
+ );
470
+ }, [querySetupState, applicationStore]);
471
+
472
+ useEffect(() => {
473
+ serviceSearchRef.current?.focus();
474
+ }, []);
475
+
476
+ return (
477
+ <div className="query-setup__wizard query-setup__existing-service-query">
478
+ <div className="query-setup__wizard__header query-setup__existing-service-query__header">
479
+ <button
480
+ className="query-setup__wizard__header__btn"
481
+ onClick={back}
482
+ title="Back to Main Menu"
483
+ >
484
+ <ArrowLeftIcon />
485
+ </button>
486
+ <div className="query-setup__wizard__header__title">
487
+ Updating an existing service query...
488
+ </div>
489
+ </div>
490
+ <div className="query-setup__wizard__content">
491
+ <div className="query-setup__wizard__group query-setup__wizard__group--inline query-setup__existing-service-query__search-bar">
492
+ <div className="query-setup__wizard__group__title">
493
+ <SearchIcon />
494
+ </div>
495
+ <CustomSelectorInput
496
+ ref={serviceSearchRef}
497
+ className="query-setup__wizard__selector"
498
+ options={serviceOptions}
499
+ isLoading={querySetupState.loadServicesState.isInProgress}
500
+ onInputChange={onSearchTextChange}
501
+ inputValue={searchText}
502
+ onChange={onServiceOptionChange}
503
+ placeholder="Search for service..."
504
+ darkMode={true}
505
+ formatOptionLabel={formatServiceOptionLabel}
506
+ />
507
+ </div>
258
508
  </div>
259
509
  </div>
260
510
  );
@@ -273,15 +523,81 @@ const buildVersionOption = (version: string): VersionOption => ({
273
523
  value: version,
274
524
  });
275
525
 
276
- const LoadServiceQuerySetup = observer(
277
- (props: { querySetupState: LoadServiceQuerySetupState }) => {
526
+ const LoadProjectServiceQuerySetup = observer(
527
+ (props: { querySetupState: LoadProjectServiceQuerySetupState }) => {
278
528
  const { querySetupState } = props;
279
529
  const applicationStore = useApplicationStore();
280
530
  const setupStore = useQuerySetupStore();
281
531
  const back = (): void => {
282
532
  setupStore.setSetupState(undefined);
283
- querySetupState.setCurrentVersionId(undefined);
284
- querySetupState.setCurrentProject(undefined);
533
+ };
534
+
535
+ // project
536
+ const projectOptions = querySetupState.projects.map(buildProjectOption);
537
+ const projectSelectorPlaceholder = querySetupState.loadProjectsState
538
+ .isInProgress
539
+ ? 'Loading projects'
540
+ : querySetupState.loadProjectsState.hasFailed
541
+ ? 'Error fetching projects'
542
+ : querySetupState.projects.length
543
+ ? 'Choose a project'
544
+ : 'You have no projects, please create or acquire access for at least one';
545
+ const onProjectOptionChange = (option: ProjectOption): void => {
546
+ querySetupState
547
+ .loadProjectServiceUpdater(option.value)
548
+ .catch(applicationStore.alertUnhandledError);
549
+ };
550
+
551
+ useEffect(() => {
552
+ flowResult(querySetupState.loadProjects()).catch(
553
+ applicationStore.alertUnhandledError,
554
+ );
555
+ }, [querySetupState, applicationStore]);
556
+
557
+ return (
558
+ <div className="query-setup__wizard query-setup__existing-service-query">
559
+ <div className="query-setup__wizard__header query-setup__service-query__header">
560
+ <button
561
+ className="query-setup__wizard__header__btn"
562
+ onClick={back}
563
+ title="Back to Main Menu"
564
+ >
565
+ <ArrowLeftIcon />
566
+ </button>
567
+ <div className="query-setup__wizard__header__title">
568
+ Load service query from a project...
569
+ </div>
570
+ </div>
571
+ <div className="query-setup__wizard__content">
572
+ <div className="query-setup__wizard__group query-setup__wizard__group--inline query-setup__existing-service-query__search-bar">
573
+ <CustomSelectorInput
574
+ className="query-setup__wizard__selector"
575
+ options={projectOptions}
576
+ disabled={
577
+ querySetupState.loadProjectsState.isInProgress ||
578
+ !projectOptions.length
579
+ }
580
+ isLoading={querySetupState.loadProjectsState.isInProgress}
581
+ onChange={onProjectOptionChange}
582
+ placeholder={projectSelectorPlaceholder}
583
+ darkMode={true}
584
+ />
585
+ </div>
586
+ </div>
587
+ </div>
588
+ );
589
+ },
590
+ );
591
+
592
+ const CloneServiceQuerySetup = observer(
593
+ (props: { querySetupState: CloneServiceQuerySetupState }) => {
594
+ const { querySetupState } = props;
595
+ const applicationStore = useApplicationStore();
596
+ const setupStore = useQuerySetupStore();
597
+
598
+ // actions
599
+ const back = (): void => {
600
+ setupStore.setSetupState(undefined);
285
601
  };
286
602
  const next = (): void => {
287
603
  if (
@@ -299,7 +615,6 @@ const LoadServiceQuerySetup = observer(
299
615
  ),
300
616
  );
301
617
  }
302
- setupStore.setSetupState(undefined);
303
618
  };
304
619
  const canProceed =
305
620
  querySetupState.currentProject &&
@@ -412,7 +727,7 @@ const LoadServiceQuerySetup = observer(
412
727
  <ArrowLeftIcon />
413
728
  </button>
414
729
  <div className="query-setup__wizard__header__title">
415
- Loading a service query...
730
+ Clone an existing service query...
416
731
  </div>
417
732
  <button
418
733
  className={clsx('query-setup__wizard__header__btn', {
@@ -420,7 +735,7 @@ const LoadServiceQuerySetup = observer(
420
735
  })}
421
736
  onClick={next}
422
737
  disabled={!canProceed}
423
- title="Proceed"
738
+ title="Create a new query"
424
739
  >
425
740
  <ArrowRightIcon />
426
741
  </button>
@@ -515,10 +830,10 @@ const CreateMappingQuerySetup = observer(
515
830
  const { querySetupState } = props;
516
831
  const applicationStore = useApplicationStore();
517
832
  const setupStore = useQuerySetupStore();
833
+
834
+ // actions
518
835
  const back = (): void => {
519
836
  setupStore.setSetupState(undefined);
520
- querySetupState.setCurrentVersionId(undefined);
521
- querySetupState.setCurrentProject(undefined);
522
837
  };
523
838
  const next = (): void => {
524
839
  if (
@@ -537,7 +852,6 @@ const CreateMappingQuerySetup = observer(
537
852
  ),
538
853
  );
539
854
  }
540
- setupStore.setSetupState(undefined);
541
855
  };
542
856
  const canProceed =
543
857
  querySetupState.currentProject &&
@@ -678,7 +992,7 @@ const CreateMappingQuerySetup = observer(
678
992
  })}
679
993
  onClick={next}
680
994
  disabled={!canProceed}
681
- title="Proceed"
995
+ title="Create a new query"
682
996
  >
683
997
  <ArrowRightIcon />
684
998
  </button>
@@ -806,10 +1120,18 @@ const QuerySetupLandingPage = observer(() => {
806
1120
  ));
807
1121
  const editQuery = (): void =>
808
1122
  setupStore.setSetupState(new EditExistingQuerySetupState(setupStore));
809
- const loadServiceQuery = (): void =>
810
- setupStore.setSetupState(new LoadServiceQuerySetupState(setupStore));
1123
+ const updateServiceQuery = (): void =>
1124
+ setupStore.setSetupState(
1125
+ new UpdateExistingServiceQuerySetupState(setupStore),
1126
+ );
1127
+ const cloneServiceQuery = (): void =>
1128
+ setupStore.setSetupState(new CloneServiceQuerySetupState(setupStore));
811
1129
  const createMappingQuery = (): void =>
812
1130
  setupStore.setSetupState(new CreateMappingQuerySetupState(setupStore));
1131
+ const loadServiceQueryFromProject = (): void =>
1132
+ setupStore.setSetupState(new LoadProjectServiceQuerySetupState(setupStore));
1133
+ const productionizeQuery = (): void =>
1134
+ setupStore.setSetupState(new QueryProductionizationSetupState(setupStore));
813
1135
 
814
1136
  useEffect(() => {
815
1137
  setupStore.initialize();
@@ -834,33 +1156,66 @@ const QuerySetupLandingPage = observer(() => {
834
1156
  onClick={editQuery}
835
1157
  >
836
1158
  <div className="query-setup__landing-page__option__icon">
837
- <PencilIcon className="query-setup__landing-page__icon--edit" />
1159
+ <ManageSearchIcon className="query-setup__landing-page__icon--search" />
838
1160
  </div>
839
1161
  <div className="query-setup__landing-page__option__label">
840
1162
  Load an existing query
841
1163
  </div>
842
1164
  </button>
843
1165
  {extraQuerySetupOptions}
1166
+ <button
1167
+ className="query-setup__landing-page__option query-setup__landing-page__option--advanced query-setup__landing-page__option--create-query"
1168
+ onClick={createMappingQuery}
1169
+ >
1170
+ <div className="query-setup__landing-page__option__icon">
1171
+ <PlusIcon />
1172
+ </div>
1173
+ <div className="query-setup__landing-page__option__label">
1174
+ Create new query on a mapping
1175
+ </div>
1176
+ </button>
844
1177
  <button
845
1178
  className="query-setup__landing-page__option query-setup__landing-page__option--advanced query-setup__landing-page__option--service-query"
846
- onClick={loadServiceQuery}
1179
+ onClick={cloneServiceQuery}
847
1180
  >
848
1181
  <div className="query-setup__landing-page__option__icon">
849
1182
  <RobotIcon />
850
1183
  </div>
851
1184
  <div className="query-setup__landing-page__option__label">
852
- Load query from a service
1185
+ Clone an existing service query
853
1186
  </div>
854
1187
  </button>
855
1188
  <button
856
- className="query-setup__landing-page__option query-setup__landing-page__option--advanced query-setup__landing-page__option--create-query"
857
- onClick={createMappingQuery}
1189
+ className="query-setup__landing-page__option query-setup__landing-page__option--advanced query-setup__landing-page__option--service-query"
1190
+ onClick={updateServiceQuery}
858
1191
  >
859
1192
  <div className="query-setup__landing-page__option__icon">
860
- <PlusIcon />
1193
+ <DroidIcon />
861
1194
  </div>
862
1195
  <div className="query-setup__landing-page__option__label">
863
- Create new query on a mapping
1196
+ Update an existing service query
1197
+ </div>
1198
+ </button>
1199
+ <button
1200
+ className="query-setup__landing-page__option query-setup__landing-page__option--advanced query-setup__landing-page__option--service-query"
1201
+ onClick={loadServiceQueryFromProject}
1202
+ >
1203
+ <div className="query-setup__landing-page__option__icon">
1204
+ <DroidIcon />
1205
+ </div>
1206
+ <div className="query-setup__landing-page__option__label">
1207
+ Load service query from a project
1208
+ </div>
1209
+ </button>
1210
+ <button
1211
+ className="query-setup__landing-page__option query-setup__landing-page__option--advanced query-setup__landing-page__option--service-query"
1212
+ onClick={productionizeQuery}
1213
+ >
1214
+ <div className="query-setup__landing-page__option__icon">
1215
+ <ArrowCirceUpIcon />
1216
+ </div>
1217
+ <div className="query-setup__landing-page__option__label">
1218
+ Productionize an existing query
864
1219
  </div>
865
1220
  </button>
866
1221
  </div>
@@ -880,10 +1235,16 @@ export const QuerySetup = withQuerySetupStore(
880
1235
  ): React.ReactNode => {
881
1236
  if (setupState instanceof EditExistingQuerySetupState) {
882
1237
  return <EditExistingQuerySetup querySetupState={setupState} />;
883
- } else if (setupState instanceof LoadServiceQuerySetupState) {
884
- return <LoadServiceQuerySetup querySetupState={setupState} />;
885
1238
  } else if (setupState instanceof CreateMappingQuerySetupState) {
886
1239
  return <CreateMappingQuerySetup querySetupState={setupState} />;
1240
+ } else if (setupState instanceof CloneServiceQuerySetupState) {
1241
+ return <CloneServiceQuerySetup querySetupState={setupState} />;
1242
+ } else if (setupState instanceof UpdateExistingServiceQuerySetupState) {
1243
+ return <UpdateExistingServiceQuerySetup querySetupState={setupState} />;
1244
+ } else if (setupState instanceof LoadProjectServiceQuerySetupState) {
1245
+ return <LoadProjectServiceQuerySetup querySetupState={setupState} />;
1246
+ } else if (setupState instanceof QueryProductionizationSetupState) {
1247
+ return <QueryProductionizationSetup querySetupState={setupState} />;
887
1248
  }
888
1249
  const extraQuerySetupRenderers = setupStore.pluginManager
889
1250
  .getApplicationPlugins()
@@ -19,10 +19,7 @@ import { useLocalObservable } from 'mobx-react-lite';
19
19
  import { QuerySetupStore } from '../stores/QuerySetupStore.js';
20
20
  import { guaranteeNonNullable } from '@finos/legend-shared';
21
21
  import { useDepotServerClient } from '@finos/legend-server-depot';
22
- import {
23
- useLegendQueryApplicationStore,
24
- useLegendQueryBaseStore,
25
- } from './LegendQueryBaseStoreProvider.js';
22
+ import { useLegendQueryApplicationStore } from './LegendQueryBaseStoreProvider.js';
26
23
 
27
24
  const QuerySetupStoreContext = createContext<QuerySetupStore | undefined>(
28
25
  undefined,
@@ -33,14 +30,8 @@ export const QuerySetupStoreProvider: React.FC<{
33
30
  }> = ({ children }) => {
34
31
  const applicationStore = useLegendQueryApplicationStore();
35
32
  const depotServerClient = useDepotServerClient();
36
- const baseStore = useLegendQueryBaseStore();
37
33
  const store = useLocalObservable(
38
- () =>
39
- new QuerySetupStore(
40
- applicationStore,
41
- depotServerClient,
42
- baseStore.pluginManager,
43
- ),
34
+ () => new QuerySetupStore(applicationStore, depotServerClient),
44
35
  );
45
36
  return (
46
37
  <QuerySetupStoreContext.Provider value={store}>
package/src/index.ts CHANGED
@@ -33,6 +33,7 @@ export { QuerySetupState, QuerySetupStore } from './stores/QuerySetupStore.js';
33
33
  export { LegendQueryApplicationConfig } from './application/LegendQueryApplicationConfig.js';
34
34
  export {
35
35
  QueryEditorStore,
36
+ ExistingQueryEditorStore,
36
37
  type QueryExportConfiguration,
37
38
  } from './stores/QueryEditorStore.js';
38
39
  export {