@finos/legend-application-query 13.4.16 → 13.4.18

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 +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
  }