@finos/legend-application-query 13.4.16 → 13.4.17

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 (50) hide show
  1. package/lib/__lib__/LegendQueryEvent.d.ts +2 -1
  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__/LegendQueryUserDataHelper.d.ts +23 -3
  6. package/lib/__lib__/LegendQueryUserDataHelper.d.ts.map +1 -1
  7. package/lib/__lib__/LegendQueryUserDataHelper.js +94 -14
  8. package/lib/__lib__/LegendQueryUserDataHelper.js.map +1 -1
  9. package/lib/__lib__/LegendQueryUserDataSpaceHelper.d.ts +31 -0
  10. package/lib/__lib__/LegendQueryUserDataSpaceHelper.d.ts.map +1 -0
  11. package/lib/__lib__/LegendQueryUserDataSpaceHelper.js +54 -0
  12. package/lib/__lib__/LegendQueryUserDataSpaceHelper.js.map +1 -0
  13. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
  14. package/lib/components/Core_LegendQueryApplicationPlugin.js +29 -11
  15. package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
  16. package/lib/components/LegendQueryAppInfo.d.ts +21 -0
  17. package/lib/components/LegendQueryAppInfo.d.ts.map +1 -0
  18. package/lib/components/LegendQueryAppInfo.js +46 -0
  19. package/lib/components/LegendQueryAppInfo.js.map +1 -0
  20. package/lib/components/QueryEditor.d.ts.map +1 -1
  21. package/lib/components/QueryEditor.js +7 -6
  22. package/lib/components/QueryEditor.js.map +1 -1
  23. package/lib/components/data-space/DataSpaceQuerySetup.js +1 -1
  24. package/lib/components/data-space/DataSpaceQuerySetup.js.map +1 -1
  25. package/lib/index.css +1 -1
  26. package/lib/package.json +3 -3
  27. package/lib/stores/QueryEditorStore.d.ts +3 -0
  28. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  29. package/lib/stores/QueryEditorStore.js +13 -1
  30. package/lib/stores/QueryEditorStore.js.map +1 -1
  31. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts +2 -0
  32. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts.map +1 -1
  33. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js +21 -2
  34. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js.map +1 -1
  35. package/lib/stores/data-space/DataSpaceQuerySetupState.d.ts +10 -2
  36. package/lib/stores/data-space/DataSpaceQuerySetupState.d.ts.map +1 -1
  37. package/lib/stores/data-space/DataSpaceQuerySetupState.js +53 -3
  38. package/lib/stores/data-space/DataSpaceQuerySetupState.js.map +1 -1
  39. package/package.json +13 -13
  40. package/src/__lib__/LegendQueryEvent.ts +2 -0
  41. package/src/__lib__/LegendQueryUserDataHelper.ts +192 -18
  42. package/src/__lib__/LegendQueryUserDataSpaceHelper.ts +98 -0
  43. package/src/components/Core_LegendQueryApplicationPlugin.tsx +35 -20
  44. package/src/components/LegendQueryAppInfo.tsx +153 -0
  45. package/src/components/QueryEditor.tsx +13 -6
  46. package/src/components/data-space/DataSpaceQuerySetup.tsx +1 -1
  47. package/src/stores/QueryEditorStore.ts +19 -0
  48. package/src/stores/data-space/DataSpaceQueryCreatorStore.ts +59 -0
  49. package/src/stores/data-space/DataSpaceQuerySetupState.ts +92 -4
  50. package/tsconfig.json +2 -0
@@ -74,7 +74,6 @@ import {
74
74
  import {
75
75
  ExistingQueryEditorStore,
76
76
  QueryBuilderActionConfig_QueryApplication,
77
- createViewProjectHandler,
78
77
  createViewSDLCProjectHandler,
79
78
  } from '../stores/QueryEditorStore.js';
80
79
  import {
@@ -318,6 +317,19 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
318
317
  key: 'about-query-info',
319
318
  title: 'Get Query Info',
320
319
  label: 'About Query Info',
320
+ disableFunc: (queryBuilderState): boolean => {
321
+ if (
322
+ queryBuilderState.workflowState.actionConfig instanceof
323
+ QueryBuilderActionConfig_QueryApplication
324
+ ) {
325
+ const editorStore =
326
+ queryBuilderState.workflowState.actionConfig.editorStore;
327
+ if (editorStore instanceof ExistingQueryEditorStore) {
328
+ return false;
329
+ }
330
+ }
331
+ return true;
332
+ },
321
333
  onClick: (queryBuilderState): void => {
322
334
  if (
323
335
  queryBuilderState.workflowState.actionConfig instanceof
@@ -333,35 +345,22 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
333
345
  icon: <InfoCircleIcon />,
334
346
  },
335
347
  {
336
- key: 'about-query-project',
348
+ key: 'about-query-sdlc-project',
337
349
  title: 'Go to Project',
338
350
  label: 'Go to Project',
339
- onClick: (queryBuilderState): void => {
351
+ disableFunc: (queryBuilderState): boolean => {
340
352
  if (
341
353
  queryBuilderState.workflowState.actionConfig instanceof
342
354
  QueryBuilderActionConfig_QueryApplication
343
355
  ) {
344
356
  const editorStore =
345
357
  queryBuilderState.workflowState.actionConfig.editorStore;
346
- LegendQueryTelemetryHelper.logEvent_QueryViewProjectLaunched(
347
- editorStore.applicationStore.telemetryService,
348
- );
349
- const { groupId, artifactId, versionId } =
350
- editorStore.getProjectInfo();
351
- createViewProjectHandler(editorStore.applicationStore)(
352
- groupId,
353
- artifactId,
354
- versionId,
355
- undefined,
356
- );
358
+ if (editorStore instanceof ExistingQueryEditorStore) {
359
+ return false;
360
+ }
357
361
  }
362
+ return true;
358
363
  },
359
- icon: <InfoCircleIcon />,
360
- },
361
- {
362
- key: 'about-query-sdlc-project',
363
- title: 'Go to SDLC Project',
364
- label: 'Go to SDLC Project',
365
364
  onClick: (queryBuilderState): void => {
366
365
  if (
367
366
  queryBuilderState.workflowState.actionConfig instanceof
@@ -383,6 +382,22 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
383
382
  },
384
383
  icon: <InfoCircleIcon />,
385
384
  },
385
+ {
386
+ key: 'about-legend-query',
387
+ title: 'About Legend Query',
388
+ label: 'About Legend Query',
389
+ onClick: (queryBuilderState): void => {
390
+ if (
391
+ queryBuilderState.workflowState.actionConfig instanceof
392
+ QueryBuilderActionConfig_QueryApplication
393
+ ) {
394
+ const editorStore =
395
+ queryBuilderState.workflowState.actionConfig.editorStore;
396
+ editorStore.setShowAppInfo(true);
397
+ }
398
+ },
399
+ icon: <InfoCircleIcon />,
400
+ },
386
401
  ];
387
402
  }
388
403
 
@@ -0,0 +1,153 @@
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
+ CopyIcon,
19
+ Dialog,
20
+ InfoCircleIcon,
21
+ Modal,
22
+ ModalBody,
23
+ ModalHeader,
24
+ ModalHeaderActions,
25
+ ModalTitle,
26
+ TimesIcon,
27
+ } from '@finos/legend-art';
28
+ import { isNonNullable } from '@finos/legend-shared';
29
+ import { useQueryEditorStore } from './QueryEditorStoreProvider.js';
30
+
31
+ export const LegendQueryInfo: React.FC<{
32
+ open: boolean;
33
+ closeModal: () => void;
34
+ }> = (props) => {
35
+ const { open, closeModal } = props;
36
+ const editorStore = useQueryEditorStore();
37
+ const applicationStore = editorStore.applicationStore;
38
+ const config = applicationStore.config;
39
+ const copyInfo = (): void => {
40
+ applicationStore.clipboardService
41
+ .copyTextToClipboard(
42
+ [
43
+ `Environment: ${config.env}`,
44
+ `Version: ${config.appVersion}`,
45
+ `Revision: ${config.appVersionCommitId}`,
46
+ `Build Time: ${config.appVersionBuildTime}`,
47
+ `Engine Server: ${config.engineServerUrl}`,
48
+ `Depot Server: ${config.depotServerUrl}`,
49
+ ]
50
+ .filter(isNonNullable)
51
+ .join('\n'),
52
+ )
53
+ .then(() =>
54
+ applicationStore.notificationService.notifySuccess(
55
+ 'Copied application info to clipboard',
56
+ ),
57
+ )
58
+ .catch(applicationStore.alertUnhandledError);
59
+ };
60
+
61
+ const goToReleaseLog = (): void => {
62
+ closeModal();
63
+ applicationStore.releaseNotesService.setReleaseLog(true);
64
+ };
65
+
66
+ return (
67
+ <Dialog onClose={closeModal} open={open}>
68
+ <Modal
69
+ darkMode={
70
+ !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
71
+ }
72
+ className="modal--scrollable app__info"
73
+ >
74
+ <ModalHeader>
75
+ <ModalTitle icon={<InfoCircleIcon />} title="About Legend Query" />
76
+ <ModalHeaderActions>
77
+ <button
78
+ className="modal__header__action"
79
+ tabIndex={-1}
80
+ onClick={copyInfo}
81
+ title="Copy application info"
82
+ >
83
+ <CopyIcon />
84
+ </button>
85
+ <button
86
+ className="modal__header__action"
87
+ tabIndex={-1}
88
+ onClick={closeModal}
89
+ >
90
+ <TimesIcon />
91
+ </button>
92
+ </ModalHeaderActions>
93
+ </ModalHeader>
94
+ <ModalBody>
95
+ <div className="app__info__entry">
96
+ <div className="app__info__entry__title">Environment:</div>
97
+ <div className="app__info__entry__value">{config.env}</div>
98
+ </div>
99
+ <div className="app__info__entry">
100
+ <div className="app__info__entry__title">Version:</div>
101
+ <div className="app__info__entry__value">{config.appVersion}</div>
102
+ </div>
103
+ <div className="app__info__entry">
104
+ <div className="app__info__entry__title">Revision:</div>
105
+ <div className="app__info__entry__value">
106
+ {config.appVersionCommitId}
107
+ </div>
108
+ </div>
109
+ <div className="app__info__entry">
110
+ <div className="app__info__entry__title">Build Time:</div>
111
+ <div className="app__info__entry__value">
112
+ {config.appVersionBuildTime}
113
+ </div>
114
+ </div>
115
+ <div className="app__info__entry">
116
+ <div
117
+ onClick={goToReleaseLog}
118
+ className="app__info__entry__value app__info__entry__value__action"
119
+ >
120
+ Details of Released Versions
121
+ </div>
122
+ </div>
123
+ <div className="app__info__group">
124
+ <div className="app__info__entry">
125
+ <div className="app__info__entry__title">Engine Server:</div>
126
+ <div className="app__info__entry__value">
127
+ <a
128
+ href={config.engineServerUrl}
129
+ target="_blank"
130
+ rel="noopener noreferrer"
131
+ >
132
+ {config.engineServerUrl}
133
+ </a>
134
+ </div>
135
+ </div>
136
+ <div className="app__info__entry">
137
+ <div className="app__info__entry__title">Depot Server:</div>
138
+ <div className="app__info__entry__value">
139
+ <a
140
+ href={config.depotServerUrl}
141
+ target="_blank"
142
+ rel="noopener noreferrer"
143
+ >
144
+ {config.depotServerUrl}
145
+ </a>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ </ModalBody>
150
+ </Modal>
151
+ </Dialog>
152
+ );
153
+ };
@@ -45,7 +45,7 @@ import {
45
45
  SunIcon,
46
46
  } from '@finos/legend-art';
47
47
  import { observer } from 'mobx-react-lite';
48
- import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
48
+ import { useEffect, useMemo, useRef, useState } from 'react';
49
49
  import {
50
50
  type MappingQueryCreatorPathParams,
51
51
  type ExistingQueryEditorPathParams,
@@ -58,6 +58,8 @@ import {
58
58
  import { ExistingQueryEditorStore } from '../stores/QueryEditorStore.js';
59
59
  import {
60
60
  LEGEND_APPLICATION_COLOR_THEME,
61
+ ReleaseLogManager,
62
+ ReleaseNotesManager,
61
63
  useApplicationStore,
62
64
  } from '@finos/legend-application';
63
65
  import { useParams } from '@finos/legend-application/browser';
@@ -86,6 +88,7 @@ import { LATEST_VERSION_ALIAS } from '@finos/legend-server-depot';
86
88
  import { buildVersionOption, type VersionOption } from './QuerySetup.js';
87
89
  import { QueryEditorExistingQueryVersionRevertModal } from './QueryEdtiorExistingQueryVersionRevertModal.js';
88
90
  import { debounce, compareSemVerVersions } from '@finos/legend-shared';
91
+ import { LegendQueryInfo } from './LegendQueryAppInfo.js';
89
92
 
90
93
  const CreateQueryDialog = observer(() => {
91
94
  const editorStore = useQueryEditorStore();
@@ -585,8 +588,6 @@ export const QueryEditor = observer(() => {
585
588
  generateQuerySetupRoute(),
586
589
  ),
587
590
  );
588
- const goToReleaseLog = (): void =>
589
- applicationStore.releaseNotesService.setReleaseLog(true);
590
591
  // settings
591
592
  // NOTE: this is temporary until we find a better home for these settings in query builder
592
593
  const engineConfig =
@@ -609,6 +610,7 @@ export const QueryEditor = observer(() => {
609
610
  flowResult(editorStore.initialize()).catch(
610
611
  applicationStore.alertUnhandledError,
611
612
  );
613
+ applicationStore.releaseNotesService.updateViewedVersion();
612
614
  }, [editorStore, applicationStore]);
613
615
 
614
616
  return (
@@ -628,9 +630,6 @@ export const QueryEditor = observer(() => {
628
630
  <MenuContentItem onClick={goToQuerySetup}>
629
631
  Back to query setup
630
632
  </MenuContentItem>
631
- <MenuContentItem onClick={goToReleaseLog}>
632
- Legend Query Release Log
633
- </MenuContentItem>
634
633
  <MenuContentItem
635
634
  disabled={!appDocUrl}
636
635
  onClick={goToDocumentation}
@@ -721,6 +720,12 @@ export const QueryEditor = observer(() => {
721
720
  />
722
721
  )}
723
722
  {editorStore.queryCreatorState.showCreateModal && <CreateQueryDialog />}
723
+ {editorStore.showAppInfo && (
724
+ <LegendQueryInfo
725
+ open={editorStore.showAppInfo}
726
+ closeModal={() => editorStore.setShowAppInfo(false)}
727
+ />
728
+ )}
724
729
  {isExistingQuery &&
725
730
  editorStore.updateState.showQueryInfo &&
726
731
  editorStore.query && (
@@ -729,6 +734,8 @@ export const QueryEditor = observer(() => {
729
734
  query={editorStore.query}
730
735
  />
731
736
  )}
737
+ <ReleaseLogManager />
738
+ <ReleaseNotesManager />
732
739
  </div>
733
740
  );
734
741
  });
@@ -95,7 +95,7 @@ const DataSpaceQuerySetupSetupPanelContent = observer(
95
95
  queryBuilderState.showAdvancedSearchPanel();
96
96
 
97
97
  useEffect(() => {
98
- flowResult(queryBuilderState.loadDataSpaces()).catch(
98
+ flowResult(queryBuilderState.initializeDataSpaceSetup()).catch(
99
99
  applicationStore.alertUnhandledError,
100
100
  );
101
101
  }, [queryBuilderState, applicationStore]);
@@ -123,6 +123,7 @@ import {
123
123
  retrieveAnalyticsResultCache,
124
124
  } from '@finos/legend-extension-dsl-data-space/graph';
125
125
  import { generateDataSpaceQueryCreatorRoute } from '../__lib__/DSL_DataSpace_LegendQueryNavigation.js';
126
+ import { hasDataSpaceInfoBeenVisited } from '../__lib__/LegendQueryUserDataSpaceHelper.js';
126
127
 
127
128
  export const createViewProjectHandler =
128
129
  (applicationStore: LegendQueryApplicationStore) =>
@@ -314,6 +315,7 @@ export abstract class QueryEditorStore {
314
315
  queryCreatorState: QueryCreatorState;
315
316
  existingQueryName: string | undefined;
316
317
  showRegisterServiceModal = false;
318
+ showAppInfo = false;
317
319
 
318
320
  constructor(
319
321
  applicationStore: LegendQueryApplicationStore,
@@ -324,10 +326,12 @@ export abstract class QueryEditorStore {
324
326
  queryLoaderState: observable,
325
327
  existingQueryName: observable,
326
328
  showRegisterServiceModal: observable,
329
+ showAppInfo: observable,
327
330
  queryBuilderState: observable,
328
331
  isPerformingBlockingAction: computed,
329
332
  setExistingQueryName: action,
330
333
  setShowRegisterServiceModal: action,
334
+ setShowAppInfo: action,
331
335
  initialize: flow,
332
336
  buildGraph: flow,
333
337
  searchExistingQueryName: flow,
@@ -405,6 +409,10 @@ export abstract class QueryEditorStore {
405
409
  this.existingQueryName = val;
406
410
  }
407
411
 
412
+ setShowAppInfo(val: boolean): void {
413
+ this.showAppInfo = val;
414
+ }
415
+
408
416
  setShowRegisterServiceModal(val: boolean): void {
409
417
  this.showRegisterServiceModal = val;
410
418
  }
@@ -534,10 +542,15 @@ export abstract class QueryEditorStore {
534
542
  error,
535
543
  );
536
544
  this.applicationStore.notificationService.notifyError(error);
545
+ this.onInitializeFailure();
537
546
  this.initState.fail();
538
547
  }
539
548
  }
540
549
 
550
+ onInitializeFailure(): void {
551
+ // Do Nothing
552
+ }
553
+
541
554
  *searchExistingQueryName(searchText: string): GeneratorFn<void> {
542
555
  const isValidSearchString =
543
556
  searchText.length >= DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH;
@@ -1234,6 +1247,10 @@ export class ExistingQueryEditorStore extends QueryEditorStore {
1234
1247
  versionId: projectInfo.versionId,
1235
1248
  dataSpace: dataSpace.path,
1236
1249
  };
1250
+ const visitedDataSpaces =
1251
+ LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(
1252
+ this.applicationStore.userDataService,
1253
+ );
1237
1254
  const dataSpaceQueryBuilderState = new DataSpaceQueryBuilderState(
1238
1255
  this.applicationStore,
1239
1256
  this.graphManagerState,
@@ -1313,6 +1330,8 @@ export class ExistingQueryEditorStore extends QueryEditorStore {
1313
1330
  projectInfo,
1314
1331
  this.applicationStore.config.options.queryBuilderConfig,
1315
1332
  sourceInfo,
1333
+ (dataSpaceInfo: DataSpaceInfo) =>
1334
+ hasDataSpaceInfoBeenVisited(dataSpaceInfo, visitedDataSpaces),
1316
1335
  );
1317
1336
  const mappingModelCoverageAnalysisResult =
1318
1337
  dataSpaceAnalysisResult?.executionContextsIndex.get(
@@ -29,8 +29,11 @@ import {
29
29
  LATEST_VERSION_ALIAS,
30
30
  } from '@finos/legend-server-depot';
31
31
  import {
32
+ LogEvent,
33
+ assertErrorThrown,
32
34
  guaranteeNonNullable,
33
35
  guaranteeType,
36
+ returnUndefOnError,
34
37
  uuid,
35
38
  } from '@finos/legend-shared';
36
39
  import {
@@ -59,6 +62,13 @@ import {
59
62
  type DataSpaceInfo,
60
63
  } from '@finos/legend-extension-dsl-data-space/application';
61
64
  import { generateDataSpaceQueryCreatorRoute } from '../../__lib__/DSL_DataSpace_LegendQueryNavigation.js';
65
+ import { LegendQueryUserDataHelper } from '../../__lib__/LegendQueryUserDataHelper.js';
66
+ import {
67
+ createVisitedDataSpaceId,
68
+ hasDataSpaceInfoBeenVisited,
69
+ createSimpleVisitedDataspace,
70
+ } from '../../__lib__/LegendQueryUserDataSpaceHelper.js';
71
+ import { LEGEND_QUERY_APP_EVENT } from '../../__lib__/LegendQueryEvent.js';
62
72
 
63
73
  export class DataSpaceQueryCreatorStore extends QueryEditorStore {
64
74
  readonly groupId: string;
@@ -144,6 +154,10 @@ export class DataSpaceQueryCreatorStore extends QueryEditorStore {
144
154
  versionId: projectInfo.versionId,
145
155
  dataSpace: dataSpace.path,
146
156
  };
157
+ const visitedDataSpaces =
158
+ LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(
159
+ this.applicationStore.userDataService,
160
+ );
147
161
  const queryBuilderState = new DataSpaceQueryBuilderState(
148
162
  this.applicationStore,
149
163
  this.graphManagerState,
@@ -193,6 +207,15 @@ export class DataSpaceQueryCreatorStore extends QueryEditorStore {
193
207
  queryBuilderState.class?.path,
194
208
  ),
195
209
  );
210
+ returnUndefOnError(() =>
211
+ LegendQueryUserDataHelper.updateVisitedDataSpaceExecContext(
212
+ this.applicationStore.userDataService,
213
+ this.groupId,
214
+ this.artifactId,
215
+ dataSpace.path,
216
+ ec.name,
217
+ ),
218
+ );
196
219
  },
197
220
  (runtimeValue: Runtime) => {
198
221
  const runtimePointer = guaranteeType(runtimeValue, RuntimePointer);
@@ -235,6 +258,8 @@ export class DataSpaceQueryCreatorStore extends QueryEditorStore {
235
258
  projectInfo,
236
259
  this.applicationStore.config.options.queryBuilderConfig,
237
260
  sourceInfo,
261
+ (dataSpaceInfo: DataSpaceInfo) =>
262
+ hasDataSpaceInfoBeenVisited(dataSpaceInfo, visitedDataSpaces),
238
263
  );
239
264
  queryBuilderState.setExecutionContext(executionContext);
240
265
  queryBuilderState.propagateExecutionContextChange(executionContext);
@@ -257,9 +282,32 @@ export class DataSpaceQueryCreatorStore extends QueryEditorStore {
257
282
  );
258
283
  }
259
284
 
285
+ // add to visited dataspaces
286
+ this.addVisitedDataSpace(executionContext.name);
260
287
  return queryBuilderState;
261
288
  }
262
289
 
290
+ addVisitedDataSpace(execName: string | undefined): void {
291
+ try {
292
+ LegendQueryUserDataHelper.addVisitedDatspace(
293
+ this.applicationStore.userDataService,
294
+ createSimpleVisitedDataspace(
295
+ this.groupId,
296
+ this.artifactId,
297
+ this.versionId,
298
+ this.dataSpacePath,
299
+ execName,
300
+ ),
301
+ );
302
+ } catch (error) {
303
+ assertErrorThrown(error);
304
+ this.applicationStore.logService.warn(
305
+ LogEvent.create(LEGEND_QUERY_APP_EVENT.LOCAL_STORAGE_PERSIST_ERROR),
306
+ error.message,
307
+ );
308
+ }
309
+ }
310
+
263
311
  getPersistConfiguration(
264
312
  lambda: RawLambda,
265
313
  options?: { update?: boolean | undefined },
@@ -283,4 +331,15 @@ export class DataSpaceQueryCreatorStore extends QueryEditorStore {
283
331
  },
284
332
  };
285
333
  }
334
+
335
+ override onInitializeFailure(): void {
336
+ LegendQueryUserDataHelper.removeRecentlyViewedDataSpace(
337
+ this.applicationStore.userDataService,
338
+ createVisitedDataSpaceId(
339
+ this.groupId,
340
+ this.artifactId,
341
+ this.dataSpacePath,
342
+ ),
343
+ );
344
+ }
286
345
  }
@@ -22,13 +22,13 @@ import {
22
22
  } from '@finos/legend-server-depot';
23
23
  import type { GraphManagerState, RawLambda } from '@finos/legend-graph';
24
24
  import { type GenericLegendApplicationStore } from '@finos/legend-application';
25
- import { action, flow, makeObservable, observable } from 'mobx';
25
+ import { action, flow, flowResult, makeObservable, observable } from 'mobx';
26
26
  import {
27
27
  type QueryBuilderConfig,
28
28
  QueryBuilderState,
29
29
  QueryBuilderDataBrowserWorkflow,
30
30
  } from '@finos/legend-query-builder';
31
- import type { ProjectGAVCoordinates } from '@finos/legend-storage';
31
+ import type { Entity, ProjectGAVCoordinates } from '@finos/legend-storage';
32
32
  import {
33
33
  ActionState,
34
34
  assertErrorThrown,
@@ -51,7 +51,13 @@ import {
51
51
  import { generateDataSpaceQueryCreatorRoute } from '../../__lib__/DSL_DataSpace_LegendQueryNavigation.js';
52
52
  import { renderDataSpaceQuerySetupSetupPanelContent } from '../../components/data-space/DataSpaceQuerySetup.js';
53
53
  import { DataSpaceAdvancedSearchState } from '@finos/legend-extension-dsl-data-space/application-query';
54
+ import type { VisitedDataspace } from '../../__lib__/LegendQueryUserDataSpaceHelper.js';
55
+ import { LegendQueryUserDataHelper } from '../../__lib__/LegendQueryUserDataHelper.js';
54
56
 
57
+ type DataSpaceVisitedEntity = {
58
+ visited: VisitedDataspace;
59
+ entity: Entity;
60
+ };
55
61
  export class DataSpaceQuerySetupState extends QueryBuilderState {
56
62
  editorStore: QueryEditorStore;
57
63
  readonly depotServerClient: DepotServerClient;
@@ -107,7 +113,9 @@ export class DataSpaceQuerySetupState extends QueryBuilderState {
107
113
  advancedSearchState: observable,
108
114
  showAdvancedSearchPanel: action,
109
115
  hideAdvancedSearchPanel: action,
110
- loadDataSpaces: flow,
116
+ initializeDataSpaceSetup: flow,
117
+ redirectIfPossible: flow,
118
+ hyrdateVisitedDataSpace: flow,
111
119
  });
112
120
 
113
121
  this.editorStore = editorStore;
@@ -144,9 +152,29 @@ export class DataSpaceQuerySetupState extends QueryBuilderState {
144
152
  this.advancedSearchState = undefined;
145
153
  }
146
154
 
147
- *loadDataSpaces(): GeneratorFn<void> {
155
+ *initializeDataSpaceSetup(): GeneratorFn<void> {
148
156
  this.loadDataSpacesState.inProgress();
149
157
  try {
158
+ const hydrated = (yield flowResult(this.redirectIfPossible())) as
159
+ | DataSpaceVisitedEntity
160
+ | undefined;
161
+ if (hydrated) {
162
+ this.applicationStore.navigationService.navigator.goToLocation(
163
+ generateDataSpaceQueryCreatorRoute(
164
+ guaranteeNonNullable(hydrated.visited.groupId),
165
+ guaranteeNonNullable(hydrated.visited.artifactId),
166
+ hydrated.visited.versionId ?? LATEST_VERSION_ALIAS,
167
+ hydrated.visited.path,
168
+ hydrated.visited.execContext ??
169
+ (hydrated.entity.content.defaultExecutionContext as string),
170
+ undefined,
171
+ undefined,
172
+ ),
173
+ );
174
+ this.loadDataSpacesState.complete();
175
+ return;
176
+ }
177
+
150
178
  this.dataSpaces = (
151
179
  (yield this.depotServerClient.getEntitiesByClassifier(
152
180
  DATA_SPACE_ELEMENT_CLASSIFIER_PATH,
@@ -162,6 +190,66 @@ export class DataSpaceQuerySetupState extends QueryBuilderState {
162
190
  this.applicationStore.notificationService.notifyError(error);
163
191
  }
164
192
  }
193
+
194
+ *redirectIfPossible(): GeneratorFn<DataSpaceVisitedEntity | undefined> {
195
+ const visitedQueries =
196
+ LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(
197
+ this.applicationStore.userDataService,
198
+ );
199
+ let redirect: DataSpaceVisitedEntity | undefined = undefined;
200
+ for (let i = 0; i < visitedQueries.length; i++) {
201
+ const visited = visitedQueries[i];
202
+ if (visited) {
203
+ const hydrated = (yield flowResult(
204
+ this.hyrdateVisitedDataSpace(visited),
205
+ )) as DataSpaceVisitedEntity | undefined;
206
+ if (hydrated) {
207
+ redirect = hydrated;
208
+ break;
209
+ }
210
+ }
211
+ }
212
+ return redirect;
213
+ }
214
+
215
+ *hyrdateVisitedDataSpace(
216
+ visited: VisitedDataspace,
217
+ ): GeneratorFn<DataSpaceVisitedEntity | undefined> {
218
+ try {
219
+ const entity = (yield this.depotServerClient.getVersionEntity(
220
+ visited.groupId,
221
+ visited.artifactId,
222
+ visited.versionId ?? LATEST_VERSION_ALIAS,
223
+ visited.path,
224
+ )) as Entity;
225
+ const content = entity.content as {
226
+ executionContexts: { name: string }[];
227
+ };
228
+ if (visited.execContext) {
229
+ const found = content.executionContexts.find(
230
+ (e) => e.name === visited.execContext,
231
+ );
232
+ if (!found) {
233
+ visited.execContext = undefined;
234
+ return {
235
+ visited,
236
+ entity,
237
+ };
238
+ }
239
+ }
240
+ return {
241
+ visited,
242
+ entity,
243
+ };
244
+ } catch (error) {
245
+ assertErrorThrown(error);
246
+ LegendQueryUserDataHelper.removeRecentlyViewedDataSpace(
247
+ this.applicationStore.userDataService,
248
+ visited.id,
249
+ );
250
+ }
251
+ return undefined;
252
+ }
165
253
  }
166
254
 
167
255
  export class DataSpaceQuerySetupStore extends QueryEditorStore {
package/tsconfig.json CHANGED
@@ -57,6 +57,7 @@
57
57
  "./src/__lib__/LegendQueryNavigation.ts",
58
58
  "./src/__lib__/LegendQueryTelemetryHelper.ts",
59
59
  "./src/__lib__/LegendQueryUserDataHelper.ts",
60
+ "./src/__lib__/LegendQueryUserDataSpaceHelper.ts",
60
61
  "./src/application/Core_LegendQuery_LegendApplicationPlugin.ts",
61
62
  "./src/application/LegendQueryApplicationConfig.ts",
62
63
  "./src/application/LegendQueryPluginManager.ts",
@@ -79,6 +80,7 @@
79
80
  "./src/components/Core_LegendQueryApplicationPlugin.tsx",
80
81
  "./src/components/CreateMappingQuerySetup.tsx",
81
82
  "./src/components/EditExistingQuerySetup.tsx",
83
+ "./src/components/LegendQueryAppInfo.tsx",
82
84
  "./src/components/LegendQueryFrameworkProvider.tsx",
83
85
  "./src/components/LegendQueryWebApplication.tsx",
84
86
  "./src/components/LoadProjectServiceQuerySetup.tsx",