@finos/legend-application-query 13.4.15 → 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 (61) 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/CloneQueryServiceSetup.js +1 -2
  14. package/lib/components/CloneQueryServiceSetup.js.map +1 -1
  15. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts +1 -1
  16. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
  17. package/lib/components/Core_LegendQueryApplicationPlugin.js +58 -16
  18. package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
  19. package/lib/components/CreateMappingQuerySetup.js +1 -2
  20. package/lib/components/CreateMappingQuerySetup.js.map +1 -1
  21. package/lib/components/LegendQueryAppInfo.d.ts +21 -0
  22. package/lib/components/LegendQueryAppInfo.d.ts.map +1 -0
  23. package/lib/components/LegendQueryAppInfo.js +46 -0
  24. package/lib/components/LegendQueryAppInfo.js.map +1 -0
  25. package/lib/components/QueryEditor.d.ts.map +1 -1
  26. package/lib/components/QueryEditor.js +9 -8
  27. package/lib/components/QueryEditor.js.map +1 -1
  28. package/lib/components/QueryEdtiorExistingQueryVersionRevertModal.js +1 -1
  29. package/lib/components/QueryEdtiorExistingQueryVersionRevertModal.js.map +1 -1
  30. package/lib/components/data-space/DataSpaceQuerySetup.js +1 -1
  31. package/lib/components/data-space/DataSpaceQuerySetup.js.map +1 -1
  32. package/lib/index.css +2 -2
  33. package/lib/index.css.map +1 -1
  34. package/lib/package.json +3 -3
  35. package/lib/stores/QueryEditorStore.d.ts +3 -0
  36. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  37. package/lib/stores/QueryEditorStore.js +13 -1
  38. package/lib/stores/QueryEditorStore.js.map +1 -1
  39. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts +2 -0
  40. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts.map +1 -1
  41. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js +21 -2
  42. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js.map +1 -1
  43. package/lib/stores/data-space/DataSpaceQuerySetupState.d.ts +10 -2
  44. package/lib/stores/data-space/DataSpaceQuerySetupState.d.ts.map +1 -1
  45. package/lib/stores/data-space/DataSpaceQuerySetupState.js +53 -3
  46. package/lib/stores/data-space/DataSpaceQuerySetupState.js.map +1 -1
  47. package/package.json +13 -13
  48. package/src/__lib__/LegendQueryEvent.ts +2 -0
  49. package/src/__lib__/LegendQueryUserDataHelper.ts +192 -18
  50. package/src/__lib__/LegendQueryUserDataSpaceHelper.ts +98 -0
  51. package/src/components/CloneQueryServiceSetup.tsx +1 -1
  52. package/src/components/Core_LegendQueryApplicationPlugin.tsx +89 -41
  53. package/src/components/CreateMappingQuerySetup.tsx +1 -1
  54. package/src/components/LegendQueryAppInfo.tsx +153 -0
  55. package/src/components/QueryEditor.tsx +15 -11
  56. package/src/components/QueryEdtiorExistingQueryVersionRevertModal.tsx +1 -1
  57. package/src/components/data-space/DataSpaceQuerySetup.tsx +1 -1
  58. package/src/stores/QueryEditorStore.ts +19 -0
  59. package/src/stores/data-space/DataSpaceQueryCreatorStore.ts +59 -0
  60. package/src/stores/data-space/DataSpaceQuerySetupState.ts +92 -4
  61. package/tsconfig.json +2 -0
@@ -16,22 +16,38 @@
16
16
 
17
17
  import type { UserDataService } from '@finos/legend-application';
18
18
  import { returnUndefOnError } from '@finos/legend-shared';
19
- import { createSimpleSchema, deserialize, list, primitive } from 'serializr';
19
+ import {
20
+ createSimpleSchema,
21
+ deserialize,
22
+ list,
23
+ primitive,
24
+ raw,
25
+ } from 'serializr';
26
+ import {
27
+ createVisitedDataspaceFromInfo,
28
+ createIdFromDataSpaceInfo,
29
+ createVisitedDataSpaceId,
30
+ type SavedVisitedDataSpaces,
31
+ type VisitedDataspace,
32
+ } from './LegendQueryUserDataSpaceHelper.js';
33
+ import type { DataSpaceInfo } from '@finos/legend-extension-dsl-data-space/application';
20
34
 
21
35
  export enum LEGEND_QUERY_USER_DATA_KEY {
22
36
  RECENTLY_VIEWED_QUERIES = 'query-editor.recent-queries',
37
+ RECENTLY_VIEWED_DATASPACES = 'query-editor.recent-dataSpaces',
23
38
  }
24
39
 
25
- const USER_DATA_RECENTLY_VIEWED_QUERIES_LIMIT = 10;
26
- type RecentlyViewedQueriesData = string[];
40
+ export const USER_DATA_RECENTLY_VIEWED_QUERIES_LIMIT = 10;
41
+ export const USER_DATA_QUERY_DATASPACE_LIMIT = 10;
42
+
43
+ type SavedData = string[];
27
44
 
28
45
  export class LegendQueryUserDataHelper {
29
- static getRecentlyViewedQueries(
46
+ static getPersistedData(
30
47
  service: UserDataService,
31
- ): RecentlyViewedQueriesData {
32
- const data = service.getObjectValue(
33
- LEGEND_QUERY_USER_DATA_KEY.RECENTLY_VIEWED_QUERIES,
34
- );
48
+ key: LEGEND_QUERY_USER_DATA_KEY,
49
+ ): SavedData {
50
+ const data = service.getObjectValue(key);
35
51
  return (
36
52
  // TODO: think of a better way to deserialize this data, maybe like settings, use JSON schema
37
53
  // See https://github.com/finos/legend-studio/issues/407
@@ -45,12 +61,41 @@ export class LegendQueryUserDataHelper {
45
61
  {
46
62
  data,
47
63
  },
48
- ) as { data: RecentlyViewedQueriesData }
64
+ ) as { data: SavedData }
49
65
  ).data,
50
66
  ) ?? []
51
67
  );
52
68
  }
53
69
 
70
+ static persistValue(
71
+ service: UserDataService,
72
+ value: string,
73
+ persistedData: SavedData,
74
+ opts: {
75
+ key: LEGEND_QUERY_USER_DATA_KEY;
76
+ limit: number;
77
+ },
78
+ ): void {
79
+ const idx = persistedData.findIndex((data) => data === value);
80
+ if (idx === -1) {
81
+ if (persistedData.length >= opts.limit) {
82
+ persistedData.pop();
83
+ }
84
+ persistedData.unshift(value);
85
+ } else {
86
+ persistedData.splice(idx, 1);
87
+ persistedData.unshift(value);
88
+ }
89
+ service.persistValue(opts.key, persistedData);
90
+ }
91
+
92
+ static getRecentlyViewedQueries(service: UserDataService): SavedData {
93
+ return LegendQueryUserDataHelper.getPersistedData(
94
+ service,
95
+ LEGEND_QUERY_USER_DATA_KEY.RECENTLY_VIEWED_QUERIES,
96
+ );
97
+ }
98
+
54
99
  static removeRecentlyViewedQueries(service: UserDataService): void {
55
100
  service.persistValue(
56
101
  LEGEND_QUERY_USER_DATA_KEY.RECENTLY_VIEWED_QUERIES,
@@ -79,21 +124,150 @@ export class LegendQueryUserDataHelper {
79
124
  queryId: string,
80
125
  ): void {
81
126
  const queries = LegendQueryUserDataHelper.getRecentlyViewedQueries(service);
82
- const idx = queries.findIndex((query) => query === queryId);
127
+ LegendQueryUserDataHelper.persistValue(service, queryId, queries, {
128
+ limit: USER_DATA_RECENTLY_VIEWED_QUERIES_LIMIT,
129
+ key: LEGEND_QUERY_USER_DATA_KEY.RECENTLY_VIEWED_QUERIES,
130
+ });
131
+ }
132
+ // DataSpaces
133
+ static getRecentlyVisitedDataSpaces(
134
+ service: UserDataService,
135
+ ): SavedVisitedDataSpaces {
136
+ const data = service.getObjectValue(
137
+ LEGEND_QUERY_USER_DATA_KEY.RECENTLY_VIEWED_DATASPACES,
138
+ );
139
+ return (
140
+ // TODO: think of a better way to deserialize this data, maybe like settings, use JSON schema
141
+ // See https://github.com/finos/legend-studio/issues/407
142
+ returnUndefOnError(
143
+ () =>
144
+ (
145
+ deserialize(
146
+ createSimpleSchema({
147
+ data: raw(),
148
+ }),
149
+ {
150
+ data,
151
+ },
152
+ ) as { data: SavedVisitedDataSpaces }
153
+ ).data,
154
+ ) ?? []
155
+ );
156
+ }
157
+
158
+ static findRecentlyVisitedDataSpace(
159
+ service: UserDataService,
160
+ id: string,
161
+ ): VisitedDataspace | undefined {
162
+ return LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(service).find(
163
+ (v) => v.id === id,
164
+ );
165
+ }
166
+
167
+ static getRecentlyVisitedDataSpace(
168
+ service: UserDataService,
169
+ ): VisitedDataspace | undefined {
170
+ return LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(service)[0];
171
+ }
172
+
173
+ static persistVisitedDataspace(
174
+ service: UserDataService,
175
+ value: VisitedDataspace,
176
+ persistedData: SavedVisitedDataSpaces,
177
+ limit = USER_DATA_QUERY_DATASPACE_LIMIT,
178
+ ): void {
179
+ const key = LEGEND_QUERY_USER_DATA_KEY.RECENTLY_VIEWED_DATASPACES;
180
+ const idx = persistedData.findIndex((data) => data.id === value.id);
83
181
  if (idx === -1) {
84
- if (queries.length < USER_DATA_RECENTLY_VIEWED_QUERIES_LIMIT) {
85
- queries.unshift(queryId);
86
- } else {
87
- queries.pop();
88
- queries.unshift(queryId);
182
+ if (persistedData.length >= limit) {
183
+ persistedData.pop();
89
184
  }
185
+ persistedData.unshift(value);
90
186
  } else {
91
- queries.splice(idx, 1);
92
- queries.unshift(queryId);
187
+ persistedData.splice(idx, 1);
188
+ persistedData.unshift(value);
93
189
  }
190
+ service.persistValue(key, persistedData);
191
+ }
192
+
193
+ static removeRecentlyViewedDataSpaces(service: UserDataService): void {
194
+ service.persistValue(
195
+ LEGEND_QUERY_USER_DATA_KEY.RECENTLY_VIEWED_DATASPACES,
196
+ [],
197
+ );
198
+ }
199
+
200
+ static removeRecentlyViewedDataSpace(
201
+ service: UserDataService,
202
+ id: string,
203
+ ): void {
204
+ const dataSpaces =
205
+ LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(service);
206
+ const idx = dataSpaces.findIndex(
207
+ (visitedDataspace) => visitedDataspace.id === id,
208
+ );
209
+ if (idx === -1) {
210
+ return;
211
+ }
212
+ dataSpaces.splice(idx, 1);
94
213
  service.persistValue(
95
214
  LEGEND_QUERY_USER_DATA_KEY.RECENTLY_VIEWED_QUERIES,
96
- queries,
215
+ dataSpaces,
97
216
  );
98
217
  }
218
+
219
+ static removeDataSpace(service: UserDataService, info: DataSpaceInfo): void {
220
+ const id = createIdFromDataSpaceInfo(info);
221
+ if (id) {
222
+ LegendQueryUserDataHelper.removeRecentlyViewedDataSpace(service, id);
223
+ }
224
+ }
225
+
226
+ static addRecentlyVistedDatspace(
227
+ service: UserDataService,
228
+ info: DataSpaceInfo,
229
+ execContext: string | undefined,
230
+ ): void {
231
+ const visited = createVisitedDataspaceFromInfo(info, execContext);
232
+ if (visited) {
233
+ const dataspaces =
234
+ LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(service);
235
+ LegendQueryUserDataHelper.persistVisitedDataspace(
236
+ service,
237
+ visited,
238
+ dataspaces,
239
+ );
240
+ }
241
+ }
242
+ static addVisitedDatspace(
243
+ service: UserDataService,
244
+ visited: VisitedDataspace,
245
+ ): void {
246
+ const dataspaces =
247
+ LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces(service);
248
+ LegendQueryUserDataHelper.persistVisitedDataspace(
249
+ service,
250
+ visited,
251
+ dataspaces,
252
+ );
253
+ }
254
+
255
+ static updateVisitedDataSpaceExecContext(
256
+ service: UserDataService,
257
+ groupId: string,
258
+ artifactId: string,
259
+ dataspace: string,
260
+ exec: string,
261
+ ): boolean {
262
+ const visited = LegendQueryUserDataHelper.findRecentlyVisitedDataSpace(
263
+ service,
264
+ createVisitedDataSpaceId(groupId, artifactId, dataspace),
265
+ );
266
+ if (visited) {
267
+ visited.execContext = exec;
268
+ LegendQueryUserDataHelper.addVisitedDatspace(service, visited);
269
+ return true;
270
+ }
271
+ return false;
272
+ }
99
273
  }
@@ -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
+ );
@@ -27,6 +27,7 @@ import {
27
27
  assertErrorThrown,
28
28
  guaranteeNonNullable,
29
29
  guaranteeType,
30
+ compareSemVerVersions,
30
31
  } from '@finos/legend-shared';
31
32
  import { flowResult } from 'mobx';
32
33
  import { observer, useLocalObservable } from 'mobx-react-lite';
@@ -53,7 +54,6 @@ import {
53
54
  type ProjectOption,
54
55
  type VersionOption,
55
56
  } from './QuerySetup.js';
56
- import { compareSemVerVersions } from '@finos/legend-storage';
57
57
 
58
58
  const CloneServiceQuerySetupStoreProvider: React.FC<{
59
59
  children: React.ReactNode;
@@ -50,6 +50,8 @@ import {
50
50
  LEGEND_QUERY_ROUTE_PATTERN,
51
51
  } from '../__lib__/LegendQueryNavigation.js';
52
52
  import {
53
+ ActionAlertActionType,
54
+ ActionAlertType,
53
55
  type ApplicationPageEntry,
54
56
  type LegendApplicationSetup,
55
57
  } from '@finos/legend-application';
@@ -65,14 +67,13 @@ import {
65
67
  generateDataSpaceQueryCreatorRoute,
66
68
  generateDataSpaceQuerySetupRoute,
67
69
  } from '../__lib__/DSL_DataSpace_LegendQueryNavigation.js';
68
- import type {
69
- QueryBuilderHeaderActionConfiguration,
70
- QueryBuilderMenuActionConfiguration,
70
+ import {
71
+ type QueryBuilderHeaderActionConfiguration,
72
+ type QueryBuilderMenuActionConfiguration,
71
73
  } from '@finos/legend-query-builder';
72
74
  import {
73
75
  ExistingQueryEditorStore,
74
76
  QueryBuilderActionConfig_QueryApplication,
75
- createViewProjectHandler,
76
77
  createViewSDLCProjectHandler,
77
78
  } from '../stores/QueryEditorStore.js';
78
79
  import {
@@ -238,6 +239,7 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
238
239
  },
239
240
  ];
240
241
  }
242
+
241
243
  getExtraQueryBuilderExportMenuActionConfigurations?(): QueryBuilderMenuActionConfiguration[] {
242
244
  return [
243
245
  {
@@ -315,6 +317,19 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
315
317
  key: 'about-query-info',
316
318
  title: 'Get Query Info',
317
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
+ },
318
333
  onClick: (queryBuilderState): void => {
319
334
  if (
320
335
  queryBuilderState.workflowState.actionConfig instanceof
@@ -330,35 +345,22 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
330
345
  icon: <InfoCircleIcon />,
331
346
  },
332
347
  {
333
- key: 'about-query-project',
348
+ key: 'about-query-sdlc-project',
334
349
  title: 'Go to Project',
335
350
  label: 'Go to Project',
336
- onClick: (queryBuilderState): void => {
351
+ disableFunc: (queryBuilderState): boolean => {
337
352
  if (
338
353
  queryBuilderState.workflowState.actionConfig instanceof
339
354
  QueryBuilderActionConfig_QueryApplication
340
355
  ) {
341
356
  const editorStore =
342
357
  queryBuilderState.workflowState.actionConfig.editorStore;
343
- LegendQueryTelemetryHelper.logEvent_QueryViewProjectLaunched(
344
- editorStore.applicationStore.telemetryService,
345
- );
346
- const { groupId, artifactId, versionId } =
347
- editorStore.getProjectInfo();
348
- createViewProjectHandler(editorStore.applicationStore)(
349
- groupId,
350
- artifactId,
351
- versionId,
352
- undefined,
353
- );
358
+ if (editorStore instanceof ExistingQueryEditorStore) {
359
+ return false;
360
+ }
354
361
  }
362
+ return true;
355
363
  },
356
- icon: <InfoCircleIcon />,
357
- },
358
- {
359
- key: 'about-query-sdlc-project',
360
- title: 'Go to SDLC Project',
361
- label: 'Go to SDLC Project',
362
364
  onClick: (queryBuilderState): void => {
363
365
  if (
364
366
  queryBuilderState.workflowState.actionConfig instanceof
@@ -380,6 +382,22 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
380
382
  },
381
383
  icon: <InfoCircleIcon />,
382
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
+ },
383
401
  ];
384
402
  }
385
403
 
@@ -425,8 +443,6 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
425
443
  ) {
426
444
  const editorStore =
427
445
  queryBuilderState.workflowState.actionConfig.editorStore;
428
- const isExistingQuery =
429
- editorStore instanceof ExistingQueryEditorStore;
430
446
  const handleNewQuery = (): void => {
431
447
  if (editorStore instanceof ExistingQueryEditorStore) {
432
448
  const query = editorStore.query;
@@ -463,24 +479,50 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
463
479
  }
464
480
  }
465
481
  }
482
+ } else {
483
+ if (
484
+ queryBuilderState.changeHistoryState.canUndo ||
485
+ queryBuilderState.changeHistoryState.canRedo
486
+ ) {
487
+ queryBuilderState.applicationStore.alertService.setActionAlertInfo(
488
+ {
489
+ message:
490
+ 'Current query will be lost when creating a new query. Do you still want to proceed?',
491
+ type: ActionAlertType.CAUTION,
492
+ actions: [
493
+ {
494
+ label: 'Proceed',
495
+ type: ActionAlertActionType.PROCEED_WITH_CAUTION,
496
+ handler:
497
+ queryBuilderState.applicationStore.guardUnhandledError(
498
+ async () => queryBuilderState.resetQueryContent(),
499
+ ),
500
+ },
501
+ {
502
+ label: 'Cancel',
503
+ type: ActionAlertActionType.PROCEED,
504
+ default: true,
505
+ },
506
+ ],
507
+ },
508
+ );
509
+ } else {
510
+ queryBuilderState.resetQueryContent();
511
+ }
466
512
  }
467
513
  };
468
514
  return (
469
- <>
470
- {isExistingQuery && (
471
- <Button
472
- className="query-editor__header__action btn--dark"
473
- disabled={editorStore.isPerformingBlockingAction}
474
- onClick={handleNewQuery}
475
- title="New query"
476
- >
477
- <SaveCurrIcon />
478
- <div className="query-editor__header__action__label">
479
- New Query
480
- </div>
481
- </Button>
482
- )}
483
- </>
515
+ <Button
516
+ className="query-editor__header__action btn--dark"
517
+ disabled={editorStore.isPerformingBlockingAction}
518
+ onClick={handleNewQuery}
519
+ title="New query"
520
+ >
521
+ <SaveCurrIcon />
522
+ <div className="query-editor__header__action__label">
523
+ New Query
524
+ </div>
525
+ </Button>
484
526
  );
485
527
  }
486
528
  return undefined;
@@ -595,7 +637,13 @@ export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlu
595
637
  </div>
596
638
  );
597
639
  }
598
- return undefined;
640
+ return (
641
+ <div className="query-editor__dataspace__header">
642
+ <div className="query-editor__header__content__main query-editor__header__content__title__text query-editor__header__content__title__text--unsaved">
643
+ Unsaved Query
644
+ </div>
645
+ </div>
646
+ );
599
647
  };
600
648
  return (
601
649
  <div className="query-editor__header__content">
@@ -28,6 +28,7 @@ import {
28
28
  getNullableFirstEntry,
29
29
  guaranteeNonNullable,
30
30
  guaranteeType,
31
+ compareSemVerVersions,
31
32
  } from '@finos/legend-shared';
32
33
  import { flowResult } from 'mobx';
33
34
  import { observer, useLocalObservable } from 'mobx-react-lite';
@@ -51,7 +52,6 @@ import {
51
52
  type ProjectOption,
52
53
  type VersionOption,
53
54
  } from './QuerySetup.js';
54
- import { compareSemVerVersions } from '@finos/legend-storage';
55
55
  import type { Mapping, PackageableRuntime } from '@finos/legend-graph';
56
56
  import {
57
57
  buildElementOption,