@finos/legend-application-query 13.4.16 → 13.4.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) 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 +8 -7
  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 +2 -2
  26. package/lib/index.css.map +1 -1
  27. package/lib/package.json +3 -3
  28. package/lib/stores/QueryEditorStore.d.ts +3 -0
  29. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  30. package/lib/stores/QueryEditorStore.js +13 -1
  31. package/lib/stores/QueryEditorStore.js.map +1 -1
  32. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts +2 -0
  33. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts.map +1 -1
  34. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js +21 -2
  35. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js.map +1 -1
  36. package/lib/stores/data-space/DataSpaceQuerySetupState.d.ts +10 -2
  37. package/lib/stores/data-space/DataSpaceQuerySetupState.d.ts.map +1 -1
  38. package/lib/stores/data-space/DataSpaceQuerySetupState.js +53 -3
  39. package/lib/stores/data-space/DataSpaceQuerySetupState.js.map +1 -1
  40. package/package.json +13 -13
  41. package/src/__lib__/LegendQueryEvent.ts +2 -0
  42. package/src/__lib__/LegendQueryUserDataHelper.ts +192 -18
  43. package/src/__lib__/LegendQueryUserDataSpaceHelper.ts +98 -0
  44. package/src/components/Core_LegendQueryApplicationPlugin.tsx +35 -20
  45. package/src/components/LegendQueryAppInfo.tsx +153 -0
  46. package/src/components/QueryEditor.tsx +18 -9
  47. package/src/components/data-space/DataSpaceQuerySetup.tsx +1 -1
  48. package/src/stores/QueryEditorStore.ts +19 -0
  49. package/src/stores/data-space/DataSpaceQueryCreatorStore.ts +59 -0
  50. package/src/stores/data-space/DataSpaceQuerySetupState.ts +92 -4
  51. package/tsconfig.json +2 -0
@@ -0,0 +1,98 @@
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 type { DataSpaceInfo } from '@finos/legend-extension-dsl-data-space/application';
18
+ import { GAV_DELIMITER, generateGAVCoordinates } from '@finos/legend-storage';
19
+
20
+ export interface VisitedDataspace {
21
+ id: string;
22
+ groupId: string;
23
+ artifactId: string;
24
+ path: string;
25
+ versionId: string | undefined;
26
+ execContext?: string | undefined;
27
+ }
28
+
29
+ export type SavedVisitedDataSpaces = VisitedDataspace[];
30
+
31
+ export const createVisitedDataSpaceId = (
32
+ groupId: string,
33
+ artifactId: string,
34
+ dataSpace: string,
35
+ ): string =>
36
+ // we will consider unique dataSpace if it belongs to the same project. i.e we will not save 2 dataspaces visited for 2 different versionss
37
+ generateGAVCoordinates(groupId, artifactId, undefined) +
38
+ GAV_DELIMITER +
39
+ dataSpace;
40
+
41
+ export const createIdFromDataSpaceInfo = (
42
+ info: DataSpaceInfo,
43
+ ): string | undefined => {
44
+ const groupId = info.groupId;
45
+ const artifactId = info.artifactId;
46
+ if (groupId && artifactId) {
47
+ return createVisitedDataSpaceId(groupId, artifactId, info.path);
48
+ }
49
+ return undefined;
50
+ };
51
+
52
+ export const createSimpleVisitedDataspace = (
53
+ groupId: string,
54
+ artifactId: string,
55
+ versionId: string | undefined,
56
+ path: string,
57
+ exec: string | undefined,
58
+ ): VisitedDataspace => ({
59
+ id: createVisitedDataSpaceId(groupId, artifactId, path),
60
+ groupId,
61
+ artifactId,
62
+ versionId,
63
+ path,
64
+ execContext: exec,
65
+ });
66
+
67
+ export const createVisitedDataspaceFromInfo = (
68
+ info: DataSpaceInfo,
69
+ execContext: string | undefined,
70
+ ): VisitedDataspace | undefined => {
71
+ const groupId = info.groupId;
72
+ const artifactId = info.artifactId;
73
+ const versionId = info.versionId;
74
+ const path = info.path;
75
+ if (groupId && artifactId) {
76
+ return createSimpleVisitedDataspace(
77
+ groupId,
78
+ artifactId,
79
+ versionId,
80
+ path,
81
+ execContext,
82
+ );
83
+ }
84
+ return undefined;
85
+ };
86
+
87
+ export const hasDataSpaceInfoBeenVisited = (
88
+ val: DataSpaceInfo,
89
+ visited: SavedVisitedDataSpaces,
90
+ ): boolean =>
91
+ Boolean(
92
+ visited.find((_visit) => {
93
+ if (_visit.id === createIdFromDataSpaceInfo(val)) {
94
+ return true;
95
+ }
96
+ return false;
97
+ }),
98
+ );
@@ -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();
@@ -361,12 +364,14 @@ export const QueryEditorExistingQueryHeader = observer(
361
364
  ) : (
362
365
  <div
363
366
  onDoubleClick={enableRename}
364
- className="query-editor__header__content__main query-editor__header__content__title query-editor__header__content__title__text"
367
+ className="query-editor__header__content__main query-editor__header__content__title"
365
368
  title="Double-click to rename query"
366
369
  >
367
- {existingEditorStore.lightQuery.name}
370
+ <div className="query-editor__header__content__title__text">
371
+ {existingEditorStore.lightQuery.name}
372
+ </div>
368
373
  <button
369
- className="panel__content__form__section__list__item__edit-btn"
374
+ className="query-editor__header__conten__title__btn panel__content__form__section__list__item__edit-btn"
370
375
  onClick={enableRename}
371
376
  >
372
377
  <PencilIcon />
@@ -585,8 +590,6 @@ export const QueryEditor = observer(() => {
585
590
  generateQuerySetupRoute(),
586
591
  ),
587
592
  );
588
- const goToReleaseLog = (): void =>
589
- applicationStore.releaseNotesService.setReleaseLog(true);
590
593
  // settings
591
594
  // NOTE: this is temporary until we find a better home for these settings in query builder
592
595
  const engineConfig =
@@ -609,6 +612,7 @@ export const QueryEditor = observer(() => {
609
612
  flowResult(editorStore.initialize()).catch(
610
613
  applicationStore.alertUnhandledError,
611
614
  );
615
+ applicationStore.releaseNotesService.updateViewedVersion();
612
616
  }, [editorStore, applicationStore]);
613
617
 
614
618
  return (
@@ -628,9 +632,6 @@ export const QueryEditor = observer(() => {
628
632
  <MenuContentItem onClick={goToQuerySetup}>
629
633
  Back to query setup
630
634
  </MenuContentItem>
631
- <MenuContentItem onClick={goToReleaseLog}>
632
- Legend Query Release Log
633
- </MenuContentItem>
634
635
  <MenuContentItem
635
636
  disabled={!appDocUrl}
636
637
  onClick={goToDocumentation}
@@ -721,6 +722,12 @@ export const QueryEditor = observer(() => {
721
722
  />
722
723
  )}
723
724
  {editorStore.queryCreatorState.showCreateModal && <CreateQueryDialog />}
725
+ {editorStore.showAppInfo && (
726
+ <LegendQueryInfo
727
+ open={editorStore.showAppInfo}
728
+ closeModal={() => editorStore.setShowAppInfo(false)}
729
+ />
730
+ )}
724
731
  {isExistingQuery &&
725
732
  editorStore.updateState.showQueryInfo &&
726
733
  editorStore.query && (
@@ -729,6 +736,8 @@ export const QueryEditor = observer(() => {
729
736
  query={editorStore.query}
730
737
  />
731
738
  )}
739
+ <ReleaseLogManager />
740
+ <ReleaseNotesManager />
732
741
  </div>
733
742
  );
734
743
  });
@@ -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
  }